blob: 164d7c5ddbc9d0e294e17cdf558e4ae0d5f6dfc3 [file] [log] [blame]
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001/*
2 * Copyright (C) 2008 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
Joe Onoratoa5902522009-07-30 13:37:37 -070017package com.android.launcher2;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080018
Patrick Dubroy6569f2c2010-07-12 14:25:18 -070019import com.android.launcher.R;
Winson Chungaafa03c2010-06-11 17:34:16 -070020
Chet Haase00397b12010-10-07 11:13:10 -070021import android.animation.TimeInterpolator;
Patrick Dubroyde7658b2010-09-27 11:15:43 -070022import android.animation.ValueAnimator;
23import android.animation.ValueAnimator.AnimatorUpdateListener;
Winson Chungaafa03c2010-06-11 17:34:16 -070024import android.app.WallpaperManager;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080025import android.content.Context;
Joe Onorato79e56262009-09-21 15:23:04 -040026import android.content.res.Resources;
Winson Chungaafa03c2010-06-11 17:34:16 -070027import android.content.res.TypedArray;
28import android.graphics.Canvas;
Patrick Dubroyde7658b2010-09-27 11:15:43 -070029import android.graphics.Point;
30import android.graphics.PointF;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080031import android.graphics.Rect;
32import android.graphics.RectF;
Patrick Dubroy6569f2c2010-07-12 14:25:18 -070033import android.graphics.drawable.Drawable;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080034import android.util.AttributeSet;
35import android.view.ContextMenu;
36import android.view.MotionEvent;
37import android.view.View;
38import android.view.ViewDebug;
39import android.view.ViewGroup;
Winson Chungaafa03c2010-06-11 17:34:16 -070040import android.view.animation.Animation;
Winson Chung150fbab2010-09-29 17:14:26 -070041import android.view.animation.DecelerateInterpolator;
Winson Chungaafa03c2010-06-11 17:34:16 -070042import android.view.animation.LayoutAnimationController;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080043
Adam Cohenf34bab52010-09-30 14:11:56 -070044public class CellLayout extends ViewGroup implements Dimmable {
Winson Chungaafa03c2010-06-11 17:34:16 -070045 static final String TAG = "CellLayout";
46
The Android Open Source Project31dd5032009-03-03 19:32:27 -080047 private int mCellWidth;
48 private int mCellHeight;
Winson Chungaafa03c2010-06-11 17:34:16 -070049
Winson Chungaafa03c2010-06-11 17:34:16 -070050 private int mLeftPadding;
51 private int mRightPadding;
52 private int mTopPadding;
53 private int mBottomPadding;
54
Adam Cohend22015c2010-07-26 22:02:18 -070055 private int mCountX;
56 private int mCountY;
The Android Open Source Project31dd5032009-03-03 19:32:27 -080057
58 private int mWidthGap;
59 private int mHeightGap;
60
61 private final Rect mRect = new Rect();
Patrick Dubroy8f86ddc2010-07-16 13:55:32 -070062 private final RectF mRectF = new RectF();
The Android Open Source Project31dd5032009-03-03 19:32:27 -080063 private final CellInfo mCellInfo = new CellInfo();
Winson Chungaafa03c2010-06-11 17:34:16 -070064
Patrick Dubroyde7658b2010-09-27 11:15:43 -070065 // These are temporary variables to prevent having to allocate a new object just to
66 // return an (x, y) value from helper functions. Do NOT use them to maintain other state.
Patrick Dubroy6569f2c2010-07-12 14:25:18 -070067 private final int[] mTmpCellXY = new int[2];
Patrick Dubroyde7658b2010-09-27 11:15:43 -070068 private final int[] mTmpPoint = new int[2];
69 private final PointF mTmpPointF = new PointF();
Patrick Dubroy6569f2c2010-07-12 14:25:18 -070070
The Android Open Source Project31dd5032009-03-03 19:32:27 -080071 boolean[][] mOccupied;
72
Michael Jurkadee05892010-07-27 10:01:56 -070073 private OnTouchListener mInterceptTouchListener;
74
Michael Jurka5f1c5092010-09-03 14:15:02 -070075 private float mBackgroundAlpha;
Adam Cohenf34bab52010-09-30 14:11:56 -070076
Michael Jurka5f1c5092010-09-03 14:15:02 -070077 private Drawable mBackground;
Adam Cohenf34bab52010-09-30 14:11:56 -070078 private Drawable mBackgroundMini;
79 private Drawable mBackgroundMiniHover;
Patrick Dubroy1262e362010-10-06 15:49:50 -070080 private Drawable mBackgroundHover;
81
82 // If we're actively dragging something over this screen, mHover is true
Michael Jurkaa63c4522010-08-19 13:52:27 -070083 private boolean mHover = false;
Michael Jurkadee05892010-07-27 10:01:56 -070084
Patrick Dubroyde7658b2010-09-27 11:15:43 -070085 private final Point mDragCenter = new Point();
Patrick Dubroy6569f2c2010-07-12 14:25:18 -070086
Patrick Dubroy6569f2c2010-07-12 14:25:18 -070087 private Drawable mDragRectDrawable;
88
Winson Chung150fbab2010-09-29 17:14:26 -070089 // These arrays are used to implement the drag visualization on x-large screens.
90 // They are used as circular arrays, indexed by mDragRectCurrent.
91 private Rect[] mDragRects = new Rect[8];
92 private int[] mDragRectAlphas = new int[mDragRects.length];
93 private InterruptibleInOutAnimator[] mDragRectAnims =
94 new InterruptibleInOutAnimator[mDragRects.length];
95
96 // Used as an index into the above 3 arrays; indicates which is the most current value.
97 private int mDragRectCurrent = 0;
98
Patrick Dubroyde7658b2010-09-27 11:15:43 -070099 private Drawable mCrosshairsDrawable = null;
100 private ValueAnimator mCrosshairsAnimator = null;
101 private float mCrosshairsVisibility = 0.0f;
102
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700103 // When a drag operation is in progress, holds the nearest cell to the touch point
104 private final int[] mDragCell = new int[2];
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800105
Winson Chungaafa03c2010-06-11 17:34:16 -0700106 private final WallpaperManager mWallpaperManager;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800107
108 public CellLayout(Context context) {
109 this(context, null);
110 }
111
112 public CellLayout(Context context, AttributeSet attrs) {
113 this(context, attrs, 0);
114 }
115
116 public CellLayout(Context context, AttributeSet attrs, int defStyle) {
117 super(context, attrs, defStyle);
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700118
119 // A ViewGroup usually does not draw, but CellLayout needs to draw a rectangle to show
120 // the user where a dragged item will land when dropped.
121 setWillNotDraw(false);
Michael Jurkaa63c4522010-08-19 13:52:27 -0700122
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800123 TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CellLayout, defStyle, 0);
124
125 mCellWidth = a.getDimensionPixelSize(R.styleable.CellLayout_cellWidth, 10);
126 mCellHeight = a.getDimensionPixelSize(R.styleable.CellLayout_cellHeight, 10);
Winson Chungaafa03c2010-06-11 17:34:16 -0700127
Adam Cohend22015c2010-07-26 22:02:18 -0700128 mLeftPadding =
129 a.getDimensionPixelSize(R.styleable.CellLayout_xAxisStartPadding, 10);
130 mRightPadding =
131 a.getDimensionPixelSize(R.styleable.CellLayout_xAxisEndPadding, 10);
132 mTopPadding =
133 a.getDimensionPixelSize(R.styleable.CellLayout_yAxisStartPadding, 10);
134 mBottomPadding =
135 a.getDimensionPixelSize(R.styleable.CellLayout_yAxisEndPadding, 10);
Winson Chungaafa03c2010-06-11 17:34:16 -0700136
Adam Cohend22015c2010-07-26 22:02:18 -0700137 mCountX = LauncherModel.getCellCountX();
138 mCountY = LauncherModel.getCellCountY();
Michael Jurka0280c3b2010-09-17 15:00:07 -0700139 mOccupied = new boolean[mCountX][mCountY];
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800140
141 a.recycle();
142
143 setAlwaysDrawnWithCacheEnabled(false);
144
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700145 mWallpaperManager = WallpaperManager.getInstance(context);
146
Patrick Dubroy046e7eb2010-10-06 12:14:43 -0700147 final Resources res = getResources();
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700148
Patrick Dubroy046e7eb2010-10-06 12:14:43 -0700149 if (LauncherApplication.isScreenXLarge()) {
Winson Chung150fbab2010-09-29 17:14:26 -0700150 mBackgroundMini = res.getDrawable(R.drawable.mini_home_screen_bg);
Adam Cohenf34bab52010-09-30 14:11:56 -0700151 mBackgroundMini.setFilterBitmap(true);
Winson Chung150fbab2010-09-29 17:14:26 -0700152 mBackground = res.getDrawable(R.drawable.home_screen_bg);
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700153 mBackground.setFilterBitmap(true);
Winson Chung150fbab2010-09-29 17:14:26 -0700154 mBackgroundMiniHover = res.getDrawable(R.drawable.mini_home_screen_bg_hover);
Adam Cohenf34bab52010-09-30 14:11:56 -0700155 mBackgroundMiniHover.setFilterBitmap(true);
Patrick Dubroy1262e362010-10-06 15:49:50 -0700156 mBackgroundHover = res.getDrawable(R.drawable.home_screen_bg_hover);
157 mBackgroundHover.setFilterBitmap(true);
Patrick Dubroy046e7eb2010-10-06 12:14:43 -0700158 }
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700159
Patrick Dubroy046e7eb2010-10-06 12:14:43 -0700160 // Initialize the data structures used for the drag visualization.
Winson Chung150fbab2010-09-29 17:14:26 -0700161
Patrick Dubroy046e7eb2010-10-06 12:14:43 -0700162 mDragRectDrawable = res.getDrawable(R.drawable.rounded_rect_green);
163 mCrosshairsDrawable = res.getDrawable(R.drawable.gardening_crosshairs);
Chet Haase00397b12010-10-07 11:13:10 -0700164 TimeInterpolator interp = new DecelerateInterpolator(2.5f); // Quint ease out
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700165
Patrick Dubroy046e7eb2010-10-06 12:14:43 -0700166 // Set up the animation for fading the crosshairs in and out
167 int animDuration = res.getInteger(R.integer.config_crosshairsFadeInTime);
168 mCrosshairsAnimator = new ValueAnimator<Float>(animDuration);
169 mCrosshairsAnimator.addUpdateListener(new AnimatorUpdateListener() {
170 public void onAnimationUpdate(ValueAnimator animation) {
171 mCrosshairsVisibility = ((Float) animation.getAnimatedValue()).floatValue();
172 CellLayout.this.invalidate();
173 }
174 });
175 mCrosshairsAnimator.setInterpolator(interp);
176
177 for (int i = 0; i < mDragRects.length; i++) {
178 mDragRects[i] = new Rect();
179 }
180
181 // When dragging things around the home screens, we show a green outline of
182 // where the item will land. The outlines gradually fade out, leaving a trail
183 // behind the drag path.
184 // Set up all the animations that are used to implement this fading.
185 final int duration = res.getInteger(R.integer.config_dragOutlineFadeTime);
186 final int fromAlphaValue = 0;
187 final int toAlphaValue = res.getInteger(R.integer.config_dragOutlineMaxAlpha);
188 for (int i = 0; i < mDragRectAnims.length; i++) {
189 final InterruptibleInOutAnimator anim =
190 new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue);
191 anim.setInterpolator(interp);
192 final int thisIndex = i;
193 anim.addUpdateListener(new AnimatorUpdateListener() {
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700194 public void onAnimationUpdate(ValueAnimator animation) {
Patrick Dubroy046e7eb2010-10-06 12:14:43 -0700195 mDragRectAlphas[thisIndex] = (Integer) animation.getAnimatedValue();
196 CellLayout.this.invalidate(mDragRects[thisIndex]);
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700197 }
198 });
Patrick Dubroy046e7eb2010-10-06 12:14:43 -0700199 mDragRectAnims[i] = anim;
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700200 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800201 }
202
Michael Jurkaa63c4522010-08-19 13:52:27 -0700203 public void setHover(boolean value) {
204 if (mHover != value) {
205 invalidate();
206 }
207 mHover = value;
208 }
209
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700210 private void animateCrosshairsTo(float value) {
211 final ValueAnimator anim = mCrosshairsAnimator;
212 long fullDuration = getResources().getInteger(R.integer.config_crosshairsFadeInTime);
213 anim.setDuration(fullDuration - anim.getCurrentPlayTime());
214 anim.setValues(mCrosshairsVisibility, value);
215 anim.cancel();
216 anim.start();
217 }
218
Patrick Dubroy1262e362010-10-06 15:49:50 -0700219 public void drawChildren(Canvas canvas) {
220 super.dispatchDraw(canvas);
221 }
222
Jeff Sharkey83f111d2009-04-20 21:03:13 -0700223 @Override
Patrick Dubroy1262e362010-10-06 15:49:50 -0700224 protected void onDraw(Canvas canvas) {
Michael Jurka5f1c5092010-09-03 14:15:02 -0700225 if (mBackgroundAlpha > 0.0f) {
Adam Cohenf34bab52010-09-30 14:11:56 -0700226 Drawable bg;
Patrick Dubroy1262e362010-10-06 15:49:50 -0700227 if (getScaleX() < 0.5f) {
228 bg = mHover ? mBackgroundMiniHover : mBackgroundMini;
Adam Cohenf34bab52010-09-30 14:11:56 -0700229 } else {
Patrick Dubroy1262e362010-10-06 15:49:50 -0700230 bg = mHover ? mBackgroundHover : mBackground;
Adam Cohenf34bab52010-09-30 14:11:56 -0700231 }
Adam Cohen9c4949e2010-10-05 12:27:22 -0700232 if (bg != null) {
233 bg.setAlpha((int) (mBackgroundAlpha * 255));
234 bg.draw(canvas);
235 }
Michael Jurkaa63c4522010-08-19 13:52:27 -0700236 }
Romain Guya6abce82009-11-10 02:54:41 -0800237
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700238 if (mCrosshairsVisibility > 0.0f) {
239 final int countX = mCountX;
240 final int countY = mCountY;
241
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700242 final float MAX_ALPHA = 0.4f;
243 final int MAX_VISIBLE_DISTANCE = 600;
244 final float DISTANCE_MULTIPLIER = 0.002f;
245
246 final Drawable d = mCrosshairsDrawable;
247 final int width = d.getIntrinsicWidth();
248 final int height = d.getIntrinsicHeight();
249
250 int x = getLeftPadding() - (mWidthGap / 2) - (width / 2);
251 for (int col = 0; col <= countX; col++) {
252 int y = getTopPadding() - (mHeightGap / 2) - (height / 2);
253 for (int row = 0; row <= countY; row++) {
254 mTmpPointF.set(x - mDragCenter.x, y - mDragCenter.y);
255 float dist = mTmpPointF.length();
256 // Crosshairs further from the drag point are more faint
257 float alpha = Math.min(MAX_ALPHA,
258 DISTANCE_MULTIPLIER * (MAX_VISIBLE_DISTANCE - dist));
259 if (alpha > 0.0f) {
260 d.setBounds(x, y, x + width, y + height);
261 d.setAlpha((int) (alpha * 255 * mCrosshairsVisibility));
262 d.draw(canvas);
263 }
264 y += mCellHeight + mHeightGap;
265 }
266 x += mCellWidth + mWidthGap;
267 }
Winson Chung150fbab2010-09-29 17:14:26 -0700268
269 for (int i = 0; i < mDragRects.length; i++) {
270 int alpha = mDragRectAlphas[i];
271 if (alpha > 0) {
272 mDragRectDrawable.setAlpha(alpha);
273 mDragRectDrawable.setBounds(mDragRects[i]);
274 mDragRectDrawable.draw(canvas);
275 }
276 }
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700277 }
278 }
279
Adam Cohenf34bab52010-09-30 14:11:56 -0700280 public void setDimmableProgress(float progress) {
281 for (int i = 0; i < getChildCount(); i++) {
282 Dimmable d = (Dimmable) getChildAt(i);
283 d.setDimmableProgress(progress);
284 }
285 }
286
287 public float getDimmableProgress() {
288 if (getChildCount() > 0) {
289 return ((Dimmable) getChildAt(0)).getDimmableProgress();
290 }
291 return 0.0f;
292 }
293
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700294 @Override
Jeff Sharkey83f111d2009-04-20 21:03:13 -0700295 public void cancelLongPress() {
296 super.cancelLongPress();
297
298 // Cancel long press for all children
299 final int count = getChildCount();
300 for (int i = 0; i < count; i++) {
301 final View child = getChildAt(i);
302 child.cancelLongPress();
303 }
304 }
305
Michael Jurkadee05892010-07-27 10:01:56 -0700306 public void setOnInterceptTouchListener(View.OnTouchListener listener) {
307 mInterceptTouchListener = listener;
308 }
309
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800310 int getCountX() {
Adam Cohend22015c2010-07-26 22:02:18 -0700311 return mCountX;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800312 }
313
314 int getCountY() {
Adam Cohend22015c2010-07-26 22:02:18 -0700315 return mCountY;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800316 }
317
Winson Chungaafa03c2010-06-11 17:34:16 -0700318 public boolean addViewToCellLayout(View child, int index, int childId, LayoutParams params) {
319 final LayoutParams lp = params;
320
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800321 // Generate an id for each view, this assumes we have at most 256x256 cells
322 // per workspace screen
Adam Cohend22015c2010-07-26 22:02:18 -0700323 if (lp.cellX >= 0 && lp.cellX <= mCountX - 1 && lp.cellY >= 0 && lp.cellY <= mCountY - 1) {
Winson Chungaafa03c2010-06-11 17:34:16 -0700324 // If the horizontal or vertical span is set to -1, it is taken to
325 // mean that it spans the extent of the CellLayout
Adam Cohend22015c2010-07-26 22:02:18 -0700326 if (lp.cellHSpan < 0) lp.cellHSpan = mCountX;
327 if (lp.cellVSpan < 0) lp.cellVSpan = mCountY;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800328
Winson Chungaafa03c2010-06-11 17:34:16 -0700329 child.setId(childId);
330
Michael Jurkadee05892010-07-27 10:01:56 -0700331 // We might be in the middle or end of shrinking/fading to a dimmed view
332 // Make sure this view's alpha is set the same as all the rest of the views
Michael Jurka5f1c5092010-09-03 14:15:02 -0700333 child.setAlpha(getAlpha());
Winson Chungaafa03c2010-06-11 17:34:16 -0700334 addView(child, index, lp);
Michael Jurkadee05892010-07-27 10:01:56 -0700335
Michael Jurka0280c3b2010-09-17 15:00:07 -0700336 markCellsAsOccupiedForView(child);
337
Winson Chungaafa03c2010-06-11 17:34:16 -0700338 return true;
339 }
340 return false;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800341 }
342
343 @Override
Michael Jurka0280c3b2010-09-17 15:00:07 -0700344 public void removeAllViews() {
345 clearOccupiedCells();
346 }
347
348 @Override
349 public void removeAllViewsInLayout() {
350 clearOccupiedCells();
351 }
352
353 @Override
354 public void removeView(View view) {
355 markCellsAsUnoccupiedForView(view);
356 super.removeView(view);
357 }
358
359 @Override
360 public void removeViewAt(int index) {
361 markCellsAsUnoccupiedForView(getChildAt(index));
362 super.removeViewAt(index);
363 }
364
365 @Override
366 public void removeViewInLayout(View view) {
367 markCellsAsUnoccupiedForView(view);
368 super.removeViewInLayout(view);
369 }
370
371 @Override
372 public void removeViews(int start, int count) {
373 for (int i = start; i < start + count; i++) {
374 markCellsAsUnoccupiedForView(getChildAt(i));
375 }
376 super.removeViews(start, count);
377 }
378
379 @Override
380 public void removeViewsInLayout(int start, int count) {
381 for (int i = start; i < start + count; i++) {
382 markCellsAsUnoccupiedForView(getChildAt(i));
383 }
384 super.removeViewsInLayout(start, count);
385 }
386
387 @Override
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800388 public void requestChildFocus(View child, View focused) {
389 super.requestChildFocus(child, focused);
390 if (child != null) {
391 Rect r = new Rect();
392 child.getDrawingRect(r);
393 requestRectangleOnScreen(r);
394 }
395 }
396
397 @Override
398 protected void onAttachedToWindow() {
399 super.onAttachedToWindow();
400 mCellInfo.screen = ((ViewGroup) getParent()).indexOfChild(this);
401 }
402
Michael Jurkaaf442092010-06-10 17:01:57 -0700403 public void setTagToCellInfoForPoint(int touchX, int touchY) {
404 final CellInfo cellInfo = mCellInfo;
405 final Rect frame = mRect;
406 final int x = touchX + mScrollX;
407 final int y = touchY + mScrollY;
408 final int count = getChildCount();
409
410 boolean found = false;
411 for (int i = count - 1; i >= 0; i--) {
412 final View child = getChildAt(i);
413
414 if ((child.getVisibility()) == VISIBLE || child.getAnimation() != null) {
415 child.getHitRect(frame);
416 if (frame.contains(x, y)) {
417 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
418 cellInfo.cell = child;
419 cellInfo.cellX = lp.cellX;
420 cellInfo.cellY = lp.cellY;
421 cellInfo.spanX = lp.cellHSpan;
422 cellInfo.spanY = lp.cellVSpan;
423 cellInfo.valid = true;
424 found = true;
Michael Jurkaaf442092010-06-10 17:01:57 -0700425 break;
426 }
427 }
428 }
Winson Chungaafa03c2010-06-11 17:34:16 -0700429
Michael Jurkaaf442092010-06-10 17:01:57 -0700430 if (!found) {
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700431 final int cellXY[] = mTmpCellXY;
Michael Jurkaaf442092010-06-10 17:01:57 -0700432 pointToCellExact(x, y, cellXY);
433
Michael Jurkaaf442092010-06-10 17:01:57 -0700434 cellInfo.cell = null;
435 cellInfo.cellX = cellXY[0];
436 cellInfo.cellY = cellXY[1];
437 cellInfo.spanX = 1;
438 cellInfo.spanY = 1;
Michael Jurka0280c3b2010-09-17 15:00:07 -0700439 cellInfo.valid = cellXY[0] >= 0 && cellXY[1] >= 0 && cellXY[0] < mCountX &&
440 cellXY[1] < mCountY && !mOccupied[cellXY[0]][cellXY[1]];
Michael Jurkaaf442092010-06-10 17:01:57 -0700441 }
442 setTag(cellInfo);
443 }
444
Winson Chungaafa03c2010-06-11 17:34:16 -0700445
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800446 @Override
447 public boolean onInterceptTouchEvent(MotionEvent ev) {
Michael Jurkadee05892010-07-27 10:01:56 -0700448 if (mInterceptTouchListener != null && mInterceptTouchListener.onTouch(this, ev)) {
449 return true;
450 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800451 final int action = ev.getAction();
452 final CellInfo cellInfo = mCellInfo;
453
454 if (action == MotionEvent.ACTION_DOWN) {
Michael Jurkaaf442092010-06-10 17:01:57 -0700455 setTagToCellInfoForPoint((int) ev.getX(), (int) ev.getY());
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800456 } else if (action == MotionEvent.ACTION_UP) {
457 cellInfo.cell = null;
458 cellInfo.cellX = -1;
459 cellInfo.cellY = -1;
460 cellInfo.spanX = 0;
461 cellInfo.spanY = 0;
462 cellInfo.valid = false;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800463 setTag(cellInfo);
464 }
465
466 return false;
467 }
468
469 @Override
470 public CellInfo getTag() {
Michael Jurka0280c3b2010-09-17 15:00:07 -0700471 return (CellInfo) super.getTag();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800472 }
473
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700474 /**
475 * Check if the row 'y' is empty from columns 'left' to 'right', inclusive.
476 */
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800477 private static boolean isRowEmpty(int y, int left, int right, boolean[][] occupied) {
478 for (int x = left; x <= right; x++) {
479 if (occupied[x][y]) {
480 return false;
481 }
482 }
483 return true;
484 }
485
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800486 /**
Winson Chungaafa03c2010-06-11 17:34:16 -0700487 * Given a point, return the cell that strictly encloses that point
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800488 * @param x X coordinate of the point
489 * @param y Y coordinate of the point
490 * @param result Array of 2 ints to hold the x and y coordinate of the cell
491 */
492 void pointToCellExact(int x, int y, int[] result) {
Winson Chungaafa03c2010-06-11 17:34:16 -0700493 final int hStartPadding = getLeftPadding();
494 final int vStartPadding = getTopPadding();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800495
496 result[0] = (x - hStartPadding) / (mCellWidth + mWidthGap);
497 result[1] = (y - vStartPadding) / (mCellHeight + mHeightGap);
498
Adam Cohend22015c2010-07-26 22:02:18 -0700499 final int xAxis = mCountX;
500 final int yAxis = mCountY;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800501
502 if (result[0] < 0) result[0] = 0;
503 if (result[0] >= xAxis) result[0] = xAxis - 1;
504 if (result[1] < 0) result[1] = 0;
505 if (result[1] >= yAxis) result[1] = yAxis - 1;
506 }
Winson Chungaafa03c2010-06-11 17:34:16 -0700507
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800508 /**
509 * Given a point, return the cell that most closely encloses that point
510 * @param x X coordinate of the point
511 * @param y Y coordinate of the point
512 * @param result Array of 2 ints to hold the x and y coordinate of the cell
513 */
514 void pointToCellRounded(int x, int y, int[] result) {
515 pointToCellExact(x + (mCellWidth / 2), y + (mCellHeight / 2), result);
516 }
517
518 /**
519 * Given a cell coordinate, return the point that represents the upper left corner of that cell
Winson Chungaafa03c2010-06-11 17:34:16 -0700520 *
521 * @param cellX X coordinate of the cell
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800522 * @param cellY Y coordinate of the cell
Winson Chungaafa03c2010-06-11 17:34:16 -0700523 *
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800524 * @param result Array of 2 ints to hold the x and y coordinate of the point
525 */
526 void cellToPoint(int cellX, int cellY, int[] result) {
Winson Chungaafa03c2010-06-11 17:34:16 -0700527 final int hStartPadding = getLeftPadding();
528 final int vStartPadding = getTopPadding();
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800529
530 result[0] = hStartPadding + cellX * (mCellWidth + mWidthGap);
531 result[1] = vStartPadding + cellY * (mCellHeight + mHeightGap);
532 }
533
Romain Guy84f296c2009-11-04 15:00:44 -0800534 int getCellWidth() {
535 return mCellWidth;
536 }
537
538 int getCellHeight() {
539 return mCellHeight;
540 }
541
Romain Guy1a304a12009-11-10 00:02:32 -0800542 int getLeftPadding() {
Winson Chungaafa03c2010-06-11 17:34:16 -0700543 return mLeftPadding;
Romain Guy1a304a12009-11-10 00:02:32 -0800544 }
545
546 int getTopPadding() {
Winson Chungaafa03c2010-06-11 17:34:16 -0700547 return mTopPadding;
Romain Guy1a304a12009-11-10 00:02:32 -0800548 }
549
550 int getRightPadding() {
Winson Chungaafa03c2010-06-11 17:34:16 -0700551 return mRightPadding;
Romain Guy1a304a12009-11-10 00:02:32 -0800552 }
553
554 int getBottomPadding() {
Winson Chungaafa03c2010-06-11 17:34:16 -0700555 return mBottomPadding;
Romain Guy1a304a12009-11-10 00:02:32 -0800556 }
557
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800558 @Override
559 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
560 // TODO: currently ignoring padding
Winson Chungaafa03c2010-06-11 17:34:16 -0700561
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800562 int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
Winson Chungaafa03c2010-06-11 17:34:16 -0700563 int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
564
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800565 int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
566 int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
Winson Chungaafa03c2010-06-11 17:34:16 -0700567
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800568 if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
569 throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
570 }
571
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800572 final int cellWidth = mCellWidth;
573 final int cellHeight = mCellHeight;
574
Adam Cohend22015c2010-07-26 22:02:18 -0700575 int numWidthGaps = mCountX - 1;
576 int numHeightGaps = mCountY - 1;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800577
Michael Jurka0280c3b2010-09-17 15:00:07 -0700578 int vSpaceLeft = heightSpecSize - mTopPadding - mBottomPadding - (cellHeight * mCountY);
Adam Cohend22015c2010-07-26 22:02:18 -0700579 mHeightGap = vSpaceLeft / numHeightGaps;
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800580
Michael Jurka0280c3b2010-09-17 15:00:07 -0700581 int hSpaceLeft = widthSpecSize - mLeftPadding - mRightPadding - (cellWidth * mCountX);
Adam Cohend22015c2010-07-26 22:02:18 -0700582 mWidthGap = hSpaceLeft / numWidthGaps;
Winson Chungaafa03c2010-06-11 17:34:16 -0700583
Michael Jurka5f1c5092010-09-03 14:15:02 -0700584 // center it around the min gaps
585 int minGap = Math.min(mWidthGap, mHeightGap);
586 mWidthGap = mHeightGap = minGap;
587
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800588 int count = getChildCount();
589
590 for (int i = 0; i < count; i++) {
591 View child = getChildAt(i);
592 LayoutParams lp = (LayoutParams) child.getLayoutParams();
Winson Chungaafa03c2010-06-11 17:34:16 -0700593 lp.setup(cellWidth, cellHeight, mWidthGap, mHeightGap,
594 mLeftPadding, mTopPadding);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800595
Michael Jurka0280c3b2010-09-17 15:00:07 -0700596 int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(lp.width, MeasureSpec.EXACTLY);
Winson Chungaafa03c2010-06-11 17:34:16 -0700597 int childheightMeasureSpec = MeasureSpec.makeMeasureSpec(lp.height,
598 MeasureSpec.EXACTLY);
599
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800600 child.measure(childWidthMeasureSpec, childheightMeasureSpec);
601 }
Michael Jurka5f1c5092010-09-03 14:15:02 -0700602 if (widthSpecMode == MeasureSpec.AT_MOST) {
603 int newWidth = mLeftPadding + mRightPadding + (mCountX * cellWidth) +
604 ((mCountX - 1) * minGap);
605 int newHeight = mTopPadding + mBottomPadding + (mCountY * cellHeight) +
606 ((mCountY - 1) * minGap);
607 setMeasuredDimension(newWidth, newHeight);
608 } else if (widthSpecMode == MeasureSpec.EXACTLY) {
609 setMeasuredDimension(widthSpecSize, heightSpecSize);
610 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800611 }
612
613 @Override
Michael Jurka28750fb2010-09-24 17:43:49 -0700614 protected void onLayout(boolean changed, int l, int t, int r, int b) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800615 int count = getChildCount();
616
617 for (int i = 0; i < count; i++) {
618 View child = getChildAt(i);
619 if (child.getVisibility() != GONE) {
620
621 CellLayout.LayoutParams lp = (CellLayout.LayoutParams) child.getLayoutParams();
622
623 int childLeft = lp.x;
624 int childTop = lp.y;
625 child.layout(childLeft, childTop, childLeft + lp.width, childTop + lp.height);
Romain Guy84f296c2009-11-04 15:00:44 -0800626
627 if (lp.dropped) {
628 lp.dropped = false;
629
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700630 final int[] cellXY = mTmpCellXY;
Romain Guy06762ab2010-01-25 16:51:08 -0800631 getLocationOnScreen(cellXY);
Romain Guy84f296c2009-11-04 15:00:44 -0800632 mWallpaperManager.sendWallpaperCommand(getWindowToken(), "android.home.drop",
Romain Guy06762ab2010-01-25 16:51:08 -0800633 cellXY[0] + childLeft + lp.width / 2,
634 cellXY[1] + childTop + lp.height / 2, 0, null);
Romain Guy84f296c2009-11-04 15:00:44 -0800635 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800636 }
637 }
638 }
639
640 @Override
Michael Jurkadee05892010-07-27 10:01:56 -0700641 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
642 super.onSizeChanged(w, h, oldw, oldh);
Michael Jurka5f1c5092010-09-03 14:15:02 -0700643 if (mBackground != null) {
Patrick Dubroy1262e362010-10-06 15:49:50 -0700644 mBackground.setBounds(0, 0, w, h);
645 }
646 if (mBackgroundHover != null) {
647 mBackgroundHover.setBounds(0, 0, w, h);
Michael Jurkaa63c4522010-08-19 13:52:27 -0700648 }
Adam Cohenf34bab52010-09-30 14:11:56 -0700649 if (mBackgroundMiniHover != null) {
Patrick Dubroy1262e362010-10-06 15:49:50 -0700650 mBackgroundMiniHover.setBounds(0, 0, w, h);
Adam Cohenf34bab52010-09-30 14:11:56 -0700651 }
652 if (mBackgroundMini != null) {
Patrick Dubroy1262e362010-10-06 15:49:50 -0700653 mBackgroundMini.setBounds(0, 0, w, h);
Michael Jurkaa63c4522010-08-19 13:52:27 -0700654 }
Michael Jurkadee05892010-07-27 10:01:56 -0700655 }
656
657 @Override
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800658 protected void setChildrenDrawingCacheEnabled(boolean enabled) {
659 final int count = getChildCount();
660 for (int i = 0; i < count; i++) {
661 final View view = getChildAt(i);
662 view.setDrawingCacheEnabled(enabled);
663 // Update the drawing caches
Adam Powellfefa0ce2010-05-03 10:23:50 -0700664 view.buildDrawingCache(true);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800665 }
666 }
667
668 @Override
669 protected void setChildrenDrawnWithCacheEnabled(boolean enabled) {
670 super.setChildrenDrawnWithCacheEnabled(enabled);
671 }
672
Michael Jurka5f1c5092010-09-03 14:15:02 -0700673 public float getBackgroundAlpha() {
674 return mBackgroundAlpha;
Michael Jurkadee05892010-07-27 10:01:56 -0700675 }
676
Michael Jurka5f1c5092010-09-03 14:15:02 -0700677 public void setBackgroundAlpha(float alpha) {
678 mBackgroundAlpha = alpha;
Michael Jurka0142d492010-08-25 17:46:15 -0700679 invalidate();
Michael Jurkadee05892010-07-27 10:01:56 -0700680 }
681
Michael Jurka5f1c5092010-09-03 14:15:02 -0700682 // Need to return true to let the view system know we know how to handle alpha-- this is
683 // because when our children have an alpha of 0.0f, they are still rendering their "dimmed"
684 // versions
685 @Override
686 protected boolean onSetAlpha(int alpha) {
687 return true;
688 }
689
690 public void setAlpha(float alpha) {
691 setChildrenAlpha(alpha);
692 super.setAlpha(alpha);
693 }
694
Michael Jurkadee05892010-07-27 10:01:56 -0700695 private void setChildrenAlpha(float alpha) {
Michael Jurka0142d492010-08-25 17:46:15 -0700696 final int childCount = getChildCount();
697 for (int i = 0; i < childCount; i++) {
Michael Jurkadee05892010-07-27 10:01:56 -0700698 getChildAt(i).setAlpha(alpha);
699 }
700 }
701
Michael Jurka0280c3b2010-09-17 15:00:07 -0700702 private boolean isVacantIgnoring(
703 int originX, int originY, int spanX, int spanY, View ignoreView) {
704 if (ignoreView != null) {
705 markCellsAsUnoccupiedForView(ignoreView);
706 }
Michael Jurka28750fb2010-09-24 17:43:49 -0700707 boolean isVacant = true;
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700708 for (int i = 0; i < spanY; i++) {
709 if (!isRowEmpty(originY + i, originX, originX + spanX - 1, mOccupied)) {
Michael Jurka28750fb2010-09-24 17:43:49 -0700710 isVacant = false;
711 break;
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700712 }
713 }
Michael Jurka0280c3b2010-09-17 15:00:07 -0700714 if (ignoreView != null) {
715 markCellsAsOccupiedForView(ignoreView);
716 }
Michael Jurka28750fb2010-09-24 17:43:49 -0700717 return isVacant;
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700718 }
719
Michael Jurka0280c3b2010-09-17 15:00:07 -0700720 private boolean isVacant(int originX, int originY, int spanX, int spanY) {
721 return isVacantIgnoring(originX, originY, spanX, spanY, null);
722 }
723
Patrick Dubroy440c3602010-07-13 17:50:32 -0700724 public View getChildAt(int x, int y) {
725 final int count = getChildCount();
726 for (int i = 0; i < count; i++) {
727 View child = getChildAt(i);
728 LayoutParams lp = (LayoutParams) child.getLayoutParams();
729
730 if ((lp.cellX <= x) && (x < lp.cellX + lp.cellHSpan) &&
731 (lp.cellY <= y) && (y < lp.cellY + lp.cellHSpan)) {
732 return child;
733 }
734 }
735 return null;
736 }
737
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700738 /**
Patrick Dubroy8f86ddc2010-07-16 13:55:32 -0700739 * Estimate the size that a child with the given dimensions will take in the layout.
740 */
741 void estimateChildSize(int minWidth, int minHeight, int[] result) {
742 // Assuming it's placed at 0, 0, find where the bottom right cell will land
743 rectToCell(minWidth, minHeight, result);
744
745 // Then figure out the rect it will occupy
746 cellToRect(0, 0, result[0], result[1], mRectF);
747 result[0] = (int)mRectF.width();
748 result[1] = (int)mRectF.height();
749 }
750
751 /**
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700752 * Estimate where the top left cell of the dragged item will land if it is dropped.
753 *
754 * @param originX The X value of the top left corner of the item
755 * @param originY The Y value of the top left corner of the item
756 * @param spanX The number of horizontal cells that the item spans
757 * @param spanY The number of vertical cells that the item spans
758 * @param result The estimated drop cell X and Y.
759 */
760 void estimateDropCell(int originX, int originY, int spanX, int spanY, int[] result) {
Adam Cohend22015c2010-07-26 22:02:18 -0700761 final int countX = mCountX;
762 final int countY = mCountY;
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700763
Michael Jurkaa63c4522010-08-19 13:52:27 -0700764 // pointToCellRounded takes the top left of a cell but will pad that with
765 // cellWidth/2 and cellHeight/2 when finding the matching cell
766 pointToCellRounded(originX, originY, result);
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700767
768 // If the item isn't fully on this screen, snap to the edges
769 int rightOverhang = result[0] + spanX - countX;
770 if (rightOverhang > 0) {
771 result[0] -= rightOverhang; // Snap to right
772 }
773 result[0] = Math.max(0, result[0]); // Snap to left
774 int bottomOverhang = result[1] + spanY - countY;
775 if (bottomOverhang > 0) {
776 result[1] -= bottomOverhang; // Snap to bottom
777 }
778 result[1] = Math.max(0, result[1]); // Snap to top
779 }
780
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700781 void visualizeDropLocation(View view, int originX, int originY, int spanX, int spanY) {
782 final int[] nearest = findNearestVacantArea(originX, originY, spanX, spanY, view, mDragCell);
783 mDragCenter.set(originX + (view.getWidth() / 2), originY + (view.getHeight() / 2));
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700784
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700785 if (nearest != null) {
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700786 // Find the top left corner of the rect the object will occupy
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700787 final int[] topLeft = mTmpPoint;
788 cellToPoint(nearest[0], nearest[1], topLeft);
789
790 // Need to copy these, because the next call to cellToPoint will overwrite them
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700791 final int left = topLeft[0];
792 final int top = topLeft[1];
793
Winson Chung150fbab2010-09-29 17:14:26 -0700794 final Rect dragRect = mDragRects[mDragRectCurrent];
795
796 if (dragRect.isEmpty() || left != dragRect.left || top != dragRect.top) {
797 // Now find the bottom right
798 final int[] bottomRight = mTmpPoint;
799 cellToPoint(nearest[0] + spanX - 1, nearest[1] + spanY - 1, bottomRight);
800 bottomRight[0] += mCellWidth;
801 bottomRight[1] += mCellHeight;
802
803 final int oldIndex = mDragRectCurrent;
804 mDragRectCurrent = (oldIndex + 1) % mDragRects.length;
805
806 mDragRects[mDragRectCurrent].set(left, top, bottomRight[0], bottomRight[1]);
807
808 mDragRectAnims[oldIndex].animateOut();
809 mDragRectAnims[mDragRectCurrent].animateIn();
810 }
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700811 }
812 }
813
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800814 /**
Jeff Sharkey70864282009-04-07 21:08:40 -0700815 * Find a vacant area that will fit the given bounds nearest the requested
816 * cell location. Uses Euclidean distance to score multiple vacant areas.
Winson Chungaafa03c2010-06-11 17:34:16 -0700817 *
Romain Guy51afc022009-05-04 18:03:43 -0700818 * @param pixelX The X location at which you want to search for a vacant area.
819 * @param pixelY The Y location at which you want to search for a vacant area.
Jeff Sharkey70864282009-04-07 21:08:40 -0700820 * @param spanX Horizontal span of the object.
821 * @param spanY Vertical span of the object.
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700822 * @param result Array in which to place the result, or null (in which case a new array will
823 * be allocated)
Jeff Sharkey70864282009-04-07 21:08:40 -0700824 * @return The X, Y cell of a vacant area that can contain this object,
825 * nearest the requested location.
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800826 */
Michael Jurka6a1435d2010-09-27 17:35:12 -0700827 int[] findNearestVacantArea(
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700828 int pixelX, int pixelY, int spanX, int spanY, int[] result) {
829 return findNearestVacantArea(pixelX, pixelY, spanX, spanY, null, result);
Michael Jurka6a1435d2010-09-27 17:35:12 -0700830 }
Winson Chungaafa03c2010-06-11 17:34:16 -0700831
Michael Jurka6a1435d2010-09-27 17:35:12 -0700832 /**
833 * Find a vacant area that will fit the given bounds nearest the requested
834 * cell location. Uses Euclidean distance to score multiple vacant areas.
835 *
836 * @param pixelX The X location at which you want to search for a vacant area.
837 * @param pixelY The Y location at which you want to search for a vacant area.
838 * @param spanX Horizontal span of the object.
839 * @param spanY Vertical span of the object.
Michael Jurka6a1435d2010-09-27 17:35:12 -0700840 * @param ignoreView Considers space occupied by this view as unoccupied
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700841 * @param result Previously returned value to possibly recycle.
Michael Jurka6a1435d2010-09-27 17:35:12 -0700842 * @return The X, Y cell of a vacant area that can contain this object,
843 * nearest the requested location.
844 */
845 int[] findNearestVacantArea(
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700846 int pixelX, int pixelY, int spanX, int spanY, View ignoreView, int[] result) {
Michael Jurkac6ee42e2010-09-30 12:04:50 -0700847 // mark space take by ignoreView as available (method checks if ignoreView is null)
848 markCellsAsUnoccupiedForView(ignoreView);
849
Jeff Sharkey70864282009-04-07 21:08:40 -0700850 // Keep track of best-scoring drop area
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700851 final int[] bestXY = result != null ? result : new int[2];
Jeff Sharkey70864282009-04-07 21:08:40 -0700852 double bestDistance = Double.MAX_VALUE;
Winson Chungaafa03c2010-06-11 17:34:16 -0700853
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700854 final int countX = mCountX;
855 final int countY = mCountY;
856 final boolean[][] occupied = mOccupied;
857
858 for (int x = 0; x < countX - (spanX - 1); x++) {
Michael Jurkac28de512010-08-13 11:27:44 -0700859 inner:
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700860 for (int y = 0; y < countY - (spanY - 1); y++) {
Michael Jurkac28de512010-08-13 11:27:44 -0700861 for (int i = 0; i < spanX; i++) {
862 for (int j = 0; j < spanY; j++) {
Patrick Dubroyde7658b2010-09-27 11:15:43 -0700863 if (occupied[x + i][y + j]) {
Michael Jurkac28de512010-08-13 11:27:44 -0700864 // small optimization: we can skip to below the row we just found
865 // an occupied cell
866 y += j;
867 continue inner;
868 }
869 }
870 }
871 final int[] cellXY = mTmpCellXY;
872 cellToPoint(x, y, cellXY);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800873
Michael Jurkac28de512010-08-13 11:27:44 -0700874 double distance = Math.sqrt(Math.pow(cellXY[0] - pixelX, 2)
875 + Math.pow(cellXY[1] - pixelY, 2));
876 if (distance <= bestDistance) {
877 bestDistance = distance;
878 bestXY[0] = x;
879 bestXY[1] = y;
880 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800881 }
882 }
Michael Jurkac6ee42e2010-09-30 12:04:50 -0700883 // re-mark space taken by ignoreView as occupied
884 markCellsAsOccupiedForView(ignoreView);
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800885
Winson Chungaafa03c2010-06-11 17:34:16 -0700886 // Return null if no suitable location found
Jeff Sharkey70864282009-04-07 21:08:40 -0700887 if (bestDistance < Double.MAX_VALUE) {
888 return bestXY;
889 } else {
890 return null;
891 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800892 }
Winson Chungaafa03c2010-06-11 17:34:16 -0700893
Michael Jurka0280c3b2010-09-17 15:00:07 -0700894 boolean existsEmptyCell() {
895 return findCellForSpan(null, 1, 1);
896 }
897
The Android Open Source Project31dd5032009-03-03 19:32:27 -0800898 /**
Michael Jurka0280c3b2010-09-17 15:00:07 -0700899 * Finds the upper-left coordinate of the first rectangle in the grid that can
900 * hold a cell of the specified dimensions. If intersectX and intersectY are not -1,
901 * then this method will only return coordinates for rectangles that contain the cell
902 * (intersectX, intersectY)
903 *
904 * @param cellXY The array that will contain the position of a vacant cell if such a cell
905 * can be found.
906 * @param spanX The horizontal span of the cell we want to find.
907 * @param spanY The vertical span of the cell we want to find.
908 *
909 * @return True if a vacant cell of the specified dimension was found, false otherwise.
Patrick Dubroy6569f2c2010-07-12 14:25:18 -0700910 */
Michael Jurka0280c3b2010-09-17 15:00:07 -0700911 boolean findCellForSpan(int[] cellXY, int spanX, int spanY) {
912 return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, null);
913 }
914
915 /**
916 * Like above, but ignores any cells occupied by the item "ignoreView"
917 *
918 * @param cellXY The array that will contain the position of a vacant cell if such a cell
919 * can be found.
920 * @param spanX The horizontal span of the cell we want to find.
921 * @param spanY The vertical span of the cell we want to find.
922 * @param ignoreView The home screen item we should treat as not occupying any space
923 * @return
924 */
925 boolean findCellForSpanIgnoring(int[] cellXY, int spanX, int spanY, View ignoreView) {
926 return findCellForSpanThatIntersectsIgnoring(cellXY, spanX, spanY, -1, -1, ignoreView);
927 }
928
929 /**
930 * Like above, but if intersectX and intersectY are not -1, then this method will try to
931 * return coordinates for rectangles that contain the cell [intersectX, intersectY]
932 *
933 * @param spanX The horizontal span of the cell we want to find.
934 * @param spanY The vertical span of the cell we want to find.
935 * @param ignoreView The home screen item we should treat as not occupying any space
936 * @param intersectX The X coordinate of the cell that we should try to overlap
937 * @param intersectX The Y coordinate of the cell that we should try to overlap
938 *
939 * @return True if a vacant cell of the specified dimension was found, false otherwise.
940 */
941 boolean findCellForSpanThatIntersects(int[] cellXY, int spanX, int spanY,
942 int intersectX, int intersectY) {
943 return findCellForSpanThatIntersectsIgnoring(
944 cellXY, spanX, spanY, intersectX, intersectY, null);
945 }
946
947 /**
948 * The superset of the above two methods
949 */
950 boolean findCellForSpanThatIntersectsIgnoring(int[] cellXY, int spanX, int spanY,
951 int intersectX, int intersectY, View ignoreView) {
Michael Jurkac6ee42e2010-09-30 12:04:50 -0700952 // mark space take by ignoreView as available (method checks if ignoreView is null)
953 markCellsAsUnoccupiedForView(ignoreView);
Michael Jurka0280c3b2010-09-17 15:00:07 -0700954
Michael Jurka28750fb2010-09-24 17:43:49 -0700955 boolean foundCell = false;
Michael Jurka0280c3b2010-09-17 15:00:07 -0700956 while (true) {
957 int startX = 0;
958 if (intersectX >= 0) {
959 startX = Math.max(startX, intersectX - (spanX - 1));
960 }
961 int endX = mCountX - (spanX - 1);
962 if (intersectX >= 0) {
963 endX = Math.min(endX, intersectX + (spanX - 1) + (spanX == 1 ? 1 : 0));
964 }
965 int startY = 0;
966 if (intersectY >= 0) {
967 startY = Math.max(startY, intersectY - (spanY - 1));
968 }
969 int endY = mCountY - (spanY - 1);
970 if (intersectY >= 0) {
971 endY = Math.min(endY, intersectY + (spanY - 1) + (spanY == 1 ? 1 : 0));
972 }
973
974 for (int x = startX; x < endX; x++) {
975 inner:
976 for (int y = startY; y < endY; y++) {
977 for (int i = 0; i < spanX; i++) {
978 for (int j = 0; j < spanY; j++) {
979 if (mOccupied[x + i][y + j]) {
980 // small optimization: we can skip to below the row we just found
981 // an occupied cell
982 y += j;
983 continue inner;
984 }
985 }
986 }
987 if (cellXY != null) {
988 cellXY[0] = x;
989 cellXY[1] = y;
990 }
Michael Jurka28750fb2010-09-24 17:43:49 -0700991 foundCell = true;
992 break;
Michael Jurka0280c3b2010-09-17 15:00:07 -0700993 }
994 }
995 if (intersectX == -1 && intersectY == -1) {
996 break;
997 } else {
998 // if we failed to find anything, try again but without any requirements of
999 // intersecting
1000 intersectX = -1;
1001 intersectY = -1;
1002 continue;
1003 }
1004 }
1005
Michael Jurkac6ee42e2010-09-30 12:04:50 -07001006 // re-mark space taken by ignoreView as occupied
1007 markCellsAsOccupiedForView(ignoreView);
Michael Jurka28750fb2010-09-24 17:43:49 -07001008 return foundCell;
Michael Jurka0280c3b2010-09-17 15:00:07 -07001009 }
1010
1011 /**
1012 * Called when drag has left this CellLayout or has been completed (successfully or not)
1013 */
1014 void onDragExit() {
Patrick Dubroy6569f2c2010-07-12 14:25:18 -07001015 // Invalidate the drag data
1016 mDragCell[0] = -1;
1017 mDragCell[1] = -1;
1018
Michael Jurkaa63c4522010-08-19 13:52:27 -07001019 setHover(false);
Patrick Dubroyde7658b2010-09-27 11:15:43 -07001020
1021 // Fade out the drag indicators
1022 if (mCrosshairsAnimator != null) {
1023 animateCrosshairsTo(0.0f);
1024 }
Winson Chung150fbab2010-09-29 17:14:26 -07001025
1026 mDragRectAnims[mDragRectCurrent].animateOut();
1027 mDragRectCurrent = (mDragRectCurrent + 1) % mDragRects.length;
1028 mDragRects[mDragRectCurrent].setEmpty();
Patrick Dubroy6569f2c2010-07-12 14:25:18 -07001029 }
1030
1031 /**
Winson Chungaafa03c2010-06-11 17:34:16 -07001032 * Mark a child as having been dropped.
Patrick Dubroyde7658b2010-09-27 11:15:43 -07001033 * At the beginning of the drag operation, the child may have been on another
1034 * screen, but it is reparented before this method is called.
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001035 *
1036 * @param child The child that is being dropped
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001037 */
Winson Chungaafa03c2010-06-11 17:34:16 -07001038 void onDropChild(View child) {
Romain Guyd94533d2009-08-17 10:01:15 -07001039 if (child != null) {
1040 LayoutParams lp = (LayoutParams) child.getLayoutParams();
Romain Guyd94533d2009-08-17 10:01:15 -07001041 lp.isDragging = false;
Romain Guy84f296c2009-11-04 15:00:44 -08001042 lp.dropped = true;
Romain Guyd94533d2009-08-17 10:01:15 -07001043 child.requestLayout();
Romain Guyd94533d2009-08-17 10:01:15 -07001044 }
Michael Jurka0280c3b2010-09-17 15:00:07 -07001045 onDragExit();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001046 }
1047
1048 void onDropAborted(View child) {
1049 if (child != null) {
1050 ((LayoutParams) child.getLayoutParams()).isDragging = false;
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001051 }
Michael Jurka0280c3b2010-09-17 15:00:07 -07001052 onDragExit();
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001053 }
1054
1055 /**
1056 * Start dragging the specified child
Winson Chungaafa03c2010-06-11 17:34:16 -07001057 *
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001058 * @param child The child that is being dragged
1059 */
1060 void onDragChild(View child) {
1061 LayoutParams lp = (LayoutParams) child.getLayoutParams();
1062 lp.isDragging = true;
Patrick Dubroyde7658b2010-09-27 11:15:43 -07001063 }
1064
1065 /**
1066 * A drag event has begun over this layout.
1067 * It may have begun over this layout (in which case onDragChild is called first),
1068 * or it may have begun on another layout.
1069 */
1070 void onDragEnter(View dragView) {
Patrick Dubroyde7658b2010-09-27 11:15:43 -07001071 // Fade in the drag indicators
1072 if (mCrosshairsAnimator != null) {
1073 animateCrosshairsTo(1.0f);
1074 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001075 }
Winson Chungaafa03c2010-06-11 17:34:16 -07001076
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001077 /**
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001078 * Computes a bounding rectangle for a range of cells
Winson Chungaafa03c2010-06-11 17:34:16 -07001079 *
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001080 * @param cellX X coordinate of upper left corner expressed as a cell position
1081 * @param cellY Y coordinate of upper left corner expressed as a cell position
Winson Chungaafa03c2010-06-11 17:34:16 -07001082 * @param cellHSpan Width in cells
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001083 * @param cellVSpan Height in cells
Patrick Dubroy6569f2c2010-07-12 14:25:18 -07001084 * @param resultRect Rect into which to put the results
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001085 */
Patrick Dubroy6569f2c2010-07-12 14:25:18 -07001086 public void cellToRect(int cellX, int cellY, int cellHSpan, int cellVSpan, RectF resultRect) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001087 final int cellWidth = mCellWidth;
1088 final int cellHeight = mCellHeight;
1089 final int widthGap = mWidthGap;
1090 final int heightGap = mHeightGap;
Winson Chungaafa03c2010-06-11 17:34:16 -07001091
1092 final int hStartPadding = getLeftPadding();
1093 final int vStartPadding = getTopPadding();
1094
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001095 int width = cellHSpan * cellWidth + ((cellHSpan - 1) * widthGap);
1096 int height = cellVSpan * cellHeight + ((cellVSpan - 1) * heightGap);
1097
1098 int x = hStartPadding + cellX * (cellWidth + widthGap);
1099 int y = vStartPadding + cellY * (cellHeight + heightGap);
Winson Chungaafa03c2010-06-11 17:34:16 -07001100
Patrick Dubroy6569f2c2010-07-12 14:25:18 -07001101 resultRect.set(x, y, x + width, y + height);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001102 }
Winson Chungaafa03c2010-06-11 17:34:16 -07001103
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001104 /**
Winson Chungaafa03c2010-06-11 17:34:16 -07001105 * Computes the required horizontal and vertical cell spans to always
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001106 * fit the given rectangle.
Winson Chungaafa03c2010-06-11 17:34:16 -07001107 *
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001108 * @param width Width in pixels
1109 * @param height Height in pixels
Patrick Dubroy8f86ddc2010-07-16 13:55:32 -07001110 * @param result An array of length 2 in which to store the result (may be null).
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001111 */
Patrick Dubroy8f86ddc2010-07-16 13:55:32 -07001112 public int[] rectToCell(int width, int height, int[] result) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001113 // Always assume we're working with the smallest span to make sure we
1114 // reserve enough space in both orientations.
Joe Onorato79e56262009-09-21 15:23:04 -04001115 final Resources resources = getResources();
1116 int actualWidth = resources.getDimensionPixelSize(R.dimen.workspace_cell_width);
1117 int actualHeight = resources.getDimensionPixelSize(R.dimen.workspace_cell_height);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001118 int smallerSize = Math.min(actualWidth, actualHeight);
Joe Onorato79e56262009-09-21 15:23:04 -04001119
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001120 // Always round up to next largest cell
1121 int spanX = (width + smallerSize) / smallerSize;
1122 int spanY = (height + smallerSize) / smallerSize;
Joe Onorato79e56262009-09-21 15:23:04 -04001123
Patrick Dubroy8f86ddc2010-07-16 13:55:32 -07001124 if (result == null) {
1125 return new int[] { spanX, spanY };
1126 }
1127 result[0] = spanX;
1128 result[1] = spanY;
1129 return result;
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001130 }
1131
1132 /**
1133 * Find the first vacant cell, if there is one.
1134 *
1135 * @param vacant Holds the x and y coordinate of the vacant cell
1136 * @param spanX Horizontal cell span.
1137 * @param spanY Vertical cell span.
Winson Chungaafa03c2010-06-11 17:34:16 -07001138 *
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001139 * @return True if a vacant cell was found
1140 */
1141 public boolean getVacantCell(int[] vacant, int spanX, int spanY) {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001142
Michael Jurka0280c3b2010-09-17 15:00:07 -07001143 return findVacantCell(vacant, spanX, spanY, mCountX, mCountY, mOccupied);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001144 }
1145
1146 static boolean findVacantCell(int[] vacant, int spanX, int spanY,
1147 int xCount, int yCount, boolean[][] occupied) {
1148
1149 for (int x = 0; x < xCount; x++) {
1150 for (int y = 0; y < yCount; y++) {
1151 boolean available = !occupied[x][y];
1152out: for (int i = x; i < x + spanX - 1 && x < xCount; i++) {
1153 for (int j = y; j < y + spanY - 1 && y < yCount; j++) {
1154 available = available && !occupied[i][j];
1155 if (!available) break out;
1156 }
1157 }
1158
1159 if (available) {
1160 vacant[0] = x;
1161 vacant[1] = y;
1162 return true;
1163 }
1164 }
1165 }
1166
1167 return false;
1168 }
1169
Patrick Dubroy6569f2c2010-07-12 14:25:18 -07001170 /**
1171 * Update the array of occupied cells (mOccupied), and return a flattened copy of the array.
1172 */
1173 boolean[] getOccupiedCellsFlattened() {
Adam Cohend22015c2010-07-26 22:02:18 -07001174 final int xCount = mCountX;
1175 final int yCount = mCountY;
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001176 final boolean[][] occupied = mOccupied;
1177
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001178 final boolean[] flat = new boolean[xCount * yCount];
1179 for (int y = 0; y < yCount; y++) {
1180 for (int x = 0; x < xCount; x++) {
1181 flat[y * xCount + x] = occupied[x][y];
1182 }
1183 }
1184
1185 return flat;
1186 }
1187
Michael Jurka0280c3b2010-09-17 15:00:07 -07001188 private void clearOccupiedCells() {
1189 for (int x = 0; x < mCountX; x++) {
1190 for (int y = 0; y < mCountY; y++) {
1191 mOccupied[x][y] = false;
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001192 }
1193 }
Michael Jurka0280c3b2010-09-17 15:00:07 -07001194 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001195
Michael Jurka0280c3b2010-09-17 15:00:07 -07001196 public void onMove(View view, int newCellX, int newCellY) {
1197 LayoutParams lp = (LayoutParams) view.getLayoutParams();
1198 markCellsAsUnoccupiedForView(view);
1199 markCellsForView(newCellX, newCellY, lp.cellHSpan, lp.cellVSpan, true);
1200 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001201
Michael Jurka0280c3b2010-09-17 15:00:07 -07001202 private void markCellsAsOccupiedForView(View view) {
Michael Jurkac6ee42e2010-09-30 12:04:50 -07001203 if (view == null || view.getParent() != this) return;
Michael Jurka0280c3b2010-09-17 15:00:07 -07001204 LayoutParams lp = (LayoutParams) view.getLayoutParams();
1205 markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, true);
1206 }
1207
1208 private void markCellsAsUnoccupiedForView(View view) {
Michael Jurkac6ee42e2010-09-30 12:04:50 -07001209 if (view == null || view.getParent() != this) return;
Michael Jurka0280c3b2010-09-17 15:00:07 -07001210 LayoutParams lp = (LayoutParams) view.getLayoutParams();
1211 markCellsForView(lp.cellX, lp.cellY, lp.cellHSpan, lp.cellVSpan, false);
1212 }
1213
1214 private void markCellsForView(int cellX, int cellY, int spanX, int spanY, boolean value) {
1215 for (int x = cellX; x < cellX + spanX && x < mCountX; x++) {
1216 for (int y = cellY; y < cellY + spanY && y < mCountY; y++) {
1217 mOccupied[x][y] = value;
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001218 }
1219 }
1220 }
1221
1222 @Override
1223 public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
1224 return new CellLayout.LayoutParams(getContext(), attrs);
1225 }
1226
1227 @Override
1228 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
1229 return p instanceof CellLayout.LayoutParams;
1230 }
1231
1232 @Override
1233 protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
1234 return new CellLayout.LayoutParams(p);
1235 }
1236
Winson Chungaafa03c2010-06-11 17:34:16 -07001237 public static class CellLayoutAnimationController extends LayoutAnimationController {
1238 public CellLayoutAnimationController(Animation animation, float delay) {
1239 super(animation, delay);
1240 }
1241
1242 @Override
1243 protected long getDelayForView(View view) {
1244 return (int) (Math.random() * 150);
1245 }
1246 }
1247
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001248 public static class LayoutParams extends ViewGroup.MarginLayoutParams {
1249 /**
1250 * Horizontal location of the item in the grid.
1251 */
1252 @ViewDebug.ExportedProperty
1253 public int cellX;
1254
1255 /**
1256 * Vertical location of the item in the grid.
1257 */
1258 @ViewDebug.ExportedProperty
1259 public int cellY;
1260
1261 /**
1262 * Number of cells spanned horizontally by the item.
1263 */
1264 @ViewDebug.ExportedProperty
1265 public int cellHSpan;
1266
1267 /**
1268 * Number of cells spanned vertically by the item.
1269 */
1270 @ViewDebug.ExportedProperty
1271 public int cellVSpan;
Winson Chungaafa03c2010-06-11 17:34:16 -07001272
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001273 /**
1274 * Is this item currently being dragged
1275 */
1276 public boolean isDragging;
1277
1278 // X coordinate of the view in the layout.
1279 @ViewDebug.ExportedProperty
1280 int x;
1281 // Y coordinate of the view in the layout.
1282 @ViewDebug.ExportedProperty
1283 int y;
1284
Romain Guy84f296c2009-11-04 15:00:44 -08001285 boolean dropped;
Romain Guyfcb9e712009-10-02 16:06:52 -07001286
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001287 public LayoutParams(Context c, AttributeSet attrs) {
1288 super(c, attrs);
1289 cellHSpan = 1;
1290 cellVSpan = 1;
1291 }
1292
1293 public LayoutParams(ViewGroup.LayoutParams source) {
1294 super(source);
1295 cellHSpan = 1;
1296 cellVSpan = 1;
1297 }
Winson Chungaafa03c2010-06-11 17:34:16 -07001298
1299 public LayoutParams(LayoutParams source) {
1300 super(source);
1301 this.cellX = source.cellX;
1302 this.cellY = source.cellY;
1303 this.cellHSpan = source.cellHSpan;
1304 this.cellVSpan = source.cellVSpan;
1305 }
1306
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001307 public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
Romain Guy8f19cdd2010-01-08 15:07:00 -08001308 super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001309 this.cellX = cellX;
1310 this.cellY = cellY;
1311 this.cellHSpan = cellHSpan;
1312 this.cellVSpan = cellVSpan;
1313 }
1314
1315 public void setup(int cellWidth, int cellHeight, int widthGap, int heightGap,
1316 int hStartPadding, int vStartPadding) {
Winson Chungaafa03c2010-06-11 17:34:16 -07001317
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001318 final int myCellHSpan = cellHSpan;
1319 final int myCellVSpan = cellVSpan;
1320 final int myCellX = cellX;
1321 final int myCellY = cellY;
Winson Chungaafa03c2010-06-11 17:34:16 -07001322
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001323 width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
1324 leftMargin - rightMargin;
1325 height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
1326 topMargin - bottomMargin;
1327
1328 x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin;
1329 y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin;
1330 }
Winson Chungaafa03c2010-06-11 17:34:16 -07001331
1332 public String toString() {
1333 return "(" + this.cellX + ", " + this.cellY + ")";
1334 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001335 }
1336
Michael Jurka0280c3b2010-09-17 15:00:07 -07001337 // This class stores info for two purposes:
1338 // 1. When dragging items (mDragInfo in Workspace), we store the View, its cellX & cellY,
1339 // its spanX, spanY, and the screen it is on
1340 // 2. When long clicking on an empty cell in a CellLayout, we save information about the
1341 // cellX and cellY coordinates and which page was clicked. We then set this as a tag on
1342 // the CellLayout that was long clicked
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001343 static final class CellInfo implements ContextMenu.ContextMenuInfo {
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001344 View cell;
Michael Jurkaa63c4522010-08-19 13:52:27 -07001345 int cellX = -1;
1346 int cellY = -1;
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001347 int spanX;
1348 int spanY;
1349 int screen;
1350 boolean valid;
1351
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001352 @Override
1353 public String toString() {
Winson Chungaafa03c2010-06-11 17:34:16 -07001354 return "Cell[view=" + (cell == null ? "null" : cell.getClass())
1355 + ", x=" + cellX + ", y=" + cellY + "]";
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001356 }
1357 }
The Android Open Source Project31dd5032009-03-03 19:32:27 -08001358}