blob: e3ad9dad1621991255b8d977e9f3ec460ef2db95 [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
Daniel Sandler325dc232013-06-05 22:57:57 -040017package com.android.launcher3;
Winson Chung321e9ee2010-08-09 13:37:56 -070018
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;
Winson Chungdb1138b2011-06-30 14:39:35 -070036 private int mOriginalCellWidth;
37 private int mOriginalCellHeight;
Winson Chung321e9ee2010-08-09 13:37:56 -070038 private int mCellWidth;
39 private int mCellHeight;
Adam Cohen234c4cd2011-07-17 21:03:04 -070040 private int mOriginalWidthGap;
41 private int mOriginalHeightGap;
Winson Chungdf4b83d2010-10-20 17:49:27 -070042 private int mWidthGap;
43 private int mHeightGap;
Michael Jurka8245a862011-02-01 17:53:59 -080044 protected PagedViewCellLayoutChildren mChildren;
Winson Chung321e9ee2010-08-09 13:37:56 -070045
Winson Chung321e9ee2010-08-09 13:37:56 -070046 public PagedViewCellLayout(Context context) {
47 this(context, null);
48 }
49
50 public PagedViewCellLayout(Context context, AttributeSet attrs) {
51 this(context, attrs, 0);
52 }
53
54 public PagedViewCellLayout(Context context, AttributeSet attrs, int defStyle) {
55 super(context, attrs, defStyle);
56
Winson Chung321e9ee2010-08-09 13:37:56 -070057 setAlwaysDrawnWithCacheEnabled(false);
58
59 // setup default cell parameters
Winson Chung5f8afe62013-08-12 16:19:28 -070060 LauncherAppState app = LauncherAppState.getInstance();
61 DeviceProfile grid = app.getDynamicGrid().getDeviceProfile();
Winson Chung5f8afe62013-08-12 16:19:28 -070062 mOriginalCellWidth = mCellWidth = grid.cellWidthPx;
63 mOriginalCellHeight = mCellHeight = grid.cellHeightPx;
Winson Chung892c74d2013-08-22 16:15:50 -070064 mCellCountX = (int) grid.numColumns;
65 mCellCountY = (int) grid.numRows;
Winson Chung6032e7e2011-11-08 15:47:17 -080066 mOriginalWidthGap = mOriginalHeightGap = mWidthGap = mHeightGap = -1;
Winson Chung321e9ee2010-08-09 13:37:56 -070067
Michael Jurka8245a862011-02-01 17:53:59 -080068 mChildren = new PagedViewCellLayoutChildren(context);
69 mChildren.setCellDimensions(mCellWidth, mCellHeight);
70 mChildren.setGap(mWidthGap, mHeightGap);
71
72 addView(mChildren);
Winson Chungb3347bb2010-08-19 14:51:28 -070073 }
Winson Chung321e9ee2010-08-09 13:37:56 -070074
Patrick Dubroy244d74c2011-05-19 16:48:48 -070075 public int getCellWidth() {
76 return mCellWidth;
77 }
78
79 public int getCellHeight() {
80 return mCellHeight;
81 }
82
Winson Chung321e9ee2010-08-09 13:37:56 -070083 @Override
84 public void cancelLongPress() {
85 super.cancelLongPress();
86
87 // Cancel long press for all children
88 final int count = getChildCount();
89 for (int i = 0; i < count; i++) {
90 final View child = getChildAt(i);
91 child.cancelLongPress();
92 }
93 }
94
95 public boolean addViewToCellLayout(View child, int index, int childId,
Winson Chung6a70e9f2011-05-17 16:24:49 -070096 PagedViewCellLayout.LayoutParams params) {
Winson Chung321e9ee2010-08-09 13:37:56 -070097 final PagedViewCellLayout.LayoutParams lp = params;
98
99 // Generate an id for each view, this assumes we have at most 256x256 cells
100 // per workspace screen
101 if (lp.cellX >= 0 && lp.cellX <= (mCellCountX - 1) &&
102 lp.cellY >= 0 && (lp.cellY <= mCellCountY - 1)) {
103 // If the horizontal or vertical span is set to -1, it is taken to
104 // mean that it spans the extent of the CellLayout
105 if (lp.cellHSpan < 0) lp.cellHSpan = mCellCountX;
106 if (lp.cellVSpan < 0) lp.cellVSpan = mCellCountY;
107
108 child.setId(childId);
Michael Jurka8245a862011-02-01 17:53:59 -0800109 mChildren.addView(child, index, lp);
Winson Chung321e9ee2010-08-09 13:37:56 -0700110
Winson Chung321e9ee2010-08-09 13:37:56 -0700111 return true;
112 }
113 return false;
114 }
115
116 @Override
Michael Jurka8245a862011-02-01 17:53:59 -0800117 public void removeAllViewsOnPage() {
118 mChildren.removeAllViews();
Michael Jurka47639b92013-01-14 12:42:27 +0100119 setLayerType(LAYER_TYPE_NONE, null);
Winson Chung321e9ee2010-08-09 13:37:56 -0700120 }
121
122 @Override
Michael Jurka8245a862011-02-01 17:53:59 -0800123 public void removeViewOnPageAt(int index) {
124 mChildren.removeViewAt(index);
Michael Jurka8245a862011-02-01 17:53:59 -0800125 }
126
Winson Chungc6f10b92011-11-14 11:39:07 -0800127 /**
128 * Clears all the key listeners for the individual icons.
129 */
130 public void resetChildrenOnKeyListeners() {
131 int childCount = mChildren.getChildCount();
132 for (int j = 0; j < childCount; ++j) {
133 mChildren.getChildAt(j).setOnKeyListener(null);
134 }
135 }
136
Michael Jurka8245a862011-02-01 17:53:59 -0800137 @Override
138 public int getPageChildCount() {
139 return mChildren.getChildCount();
140 }
141
Winson Chung5afbf7b2011-07-25 11:53:08 -0700142 public PagedViewCellLayoutChildren getChildrenLayout() {
143 return mChildren;
144 }
145
Michael Jurka8245a862011-02-01 17:53:59 -0800146 @Override
147 public View getChildOnPageAt(int i) {
148 return mChildren.getChildAt(i);
149 }
150
151 @Override
152 public int indexOfChildOnPage(View v) {
153 return mChildren.indexOfChild(v);
154 }
155
Winson Chung97d85d22011-04-13 11:27:36 -0700156 public int getCellCountX() {
157 return mCellCountX;
158 }
159
160 public int getCellCountY() {
161 return mCellCountY;
162 }
163
Winson Chung321e9ee2010-08-09 13:37:56 -0700164 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
Winson Chung321e9ee2010-08-09 13:37:56 -0700165 int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
166 int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
167
168 int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
169 int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);
170
171 if (widthSpecMode == MeasureSpec.UNSPECIFIED || heightSpecMode == MeasureSpec.UNSPECIFIED) {
172 throw new RuntimeException("CellLayout cannot have UNSPECIFIED dimensions");
173 }
174
Winson Chung321e9ee2010-08-09 13:37:56 -0700175 int numWidthGaps = mCellCountX - 1;
176 int numHeightGaps = mCellCountY - 1;
177
Adam Cohen234c4cd2011-07-17 21:03:04 -0700178 if (mOriginalWidthGap < 0 || mOriginalHeightGap < 0) {
Michael Jurka8b805b12012-04-18 14:23:14 -0700179 int hSpace = widthSpecSize - getPaddingLeft() - getPaddingRight();
180 int vSpace = heightSpecSize - getPaddingTop() - getPaddingBottom();
Winson Chungdb1138b2011-06-30 14:39:35 -0700181 int hFreeSpace = hSpace - (mCellCountX * mOriginalCellWidth);
182 int vFreeSpace = vSpace - (mCellCountY * mOriginalCellHeight);
Winson Chungc58497e2013-09-03 17:48:37 -0700183 mWidthGap = numWidthGaps > 0 ? (hFreeSpace / numWidthGaps) : 0;
184 mHeightGap = numHeightGaps > 0 ? (vFreeSpace / numHeightGaps) : 0;
Winson Chung321e9ee2010-08-09 13:37:56 -0700185
Winson Chungdb1138b2011-06-30 14:39:35 -0700186 mChildren.setGap(mWidthGap, mHeightGap);
Adam Cohen234c4cd2011-07-17 21:03:04 -0700187 } else {
188 mWidthGap = mOriginalWidthGap;
189 mHeightGap = mOriginalHeightGap;
Winson Chungdf4b83d2010-10-20 17:49:27 -0700190 }
Winson Chung321e9ee2010-08-09 13:37:56 -0700191
Winson Chungdb1138b2011-06-30 14:39:35 -0700192 // Initial values correspond to widthSpecMode == MeasureSpec.EXACTLY
193 int newWidth = widthSpecSize;
194 int newHeight = heightSpecSize;
195 if (widthSpecMode == MeasureSpec.AT_MOST) {
Michael Jurka8b805b12012-04-18 14:23:14 -0700196 newWidth = getPaddingLeft() + getPaddingRight() + (mCellCountX * mCellWidth) +
Winson Chungdb1138b2011-06-30 14:39:35 -0700197 ((mCellCountX - 1) * mWidthGap);
Michael Jurka8b805b12012-04-18 14:23:14 -0700198 newHeight = getPaddingTop() + getPaddingBottom() + (mCellCountY * mCellHeight) +
Winson Chungdb1138b2011-06-30 14:39:35 -0700199 ((mCellCountY - 1) * mHeightGap);
200 setMeasuredDimension(newWidth, newHeight);
201 }
Winson Chung321e9ee2010-08-09 13:37:56 -0700202
203 final int count = getChildCount();
204 for (int i = 0; i < count; i++) {
205 View child = getChildAt(i);
Michael Jurka8245a862011-02-01 17:53:59 -0800206 int childWidthMeasureSpec =
Michael Jurka8b805b12012-04-18 14:23:14 -0700207 MeasureSpec.makeMeasureSpec(newWidth - getPaddingLeft() -
208 getPaddingRight(), MeasureSpec.EXACTLY);
Michael Jurka8245a862011-02-01 17:53:59 -0800209 int childheightMeasureSpec =
Michael Jurka8b805b12012-04-18 14:23:14 -0700210 MeasureSpec.makeMeasureSpec(newHeight - getPaddingTop() -
211 getPaddingBottom(), MeasureSpec.EXACTLY);
Winson Chung321e9ee2010-08-09 13:37:56 -0700212 child.measure(childWidthMeasureSpec, childheightMeasureSpec);
213 }
214
Winson Chungdb1138b2011-06-30 14:39:35 -0700215 setMeasuredDimension(newWidth, newHeight);
Winson Chung321e9ee2010-08-09 13:37:56 -0700216 }
217
Michael Jurka7ef959b2011-02-23 11:48:32 -0800218 int getContentWidth() {
Michael Jurka8b805b12012-04-18 14:23:14 -0700219 return getWidthBeforeFirstLayout() + getPaddingLeft() + getPaddingRight();
Michael Jurka0413dfa2011-04-05 16:52:32 -0700220 }
221
Winson Chung4b576be2011-04-27 17:40:20 -0700222 int getContentHeight() {
Patrick Dubroy4a5ad092011-05-23 16:15:09 -0700223 if (mCellCountY > 0) {
224 return mCellCountY * mCellHeight + (mCellCountY - 1) * Math.max(0, mHeightGap);
225 }
226 return 0;
Winson Chung4b576be2011-04-27 17:40:20 -0700227 }
228
Michael Jurkad92e7412011-04-05 17:07:27 -0700229 int getWidthBeforeFirstLayout() {
Patrick Dubroy4a5ad092011-05-23 16:15:09 -0700230 if (mCellCountX > 0) {
231 return mCellCountX * mCellWidth + (mCellCountX - 1) * Math.max(0, mWidthGap);
232 }
233 return 0;
Michael Jurka7ef959b2011-02-23 11:48:32 -0800234 }
235
Winson Chung321e9ee2010-08-09 13:37:56 -0700236 @Override
237 protected void onLayout(boolean changed, int l, int t, int r, int b) {
238 int count = getChildCount();
Winson Chung321e9ee2010-08-09 13:37:56 -0700239 for (int i = 0; i < count; i++) {
240 View child = getChildAt(i);
Michael Jurka8b805b12012-04-18 14:23:14 -0700241 child.layout(getPaddingLeft(), getPaddingTop(),
242 r - l - getPaddingRight(), b - t - getPaddingBottom());
Winson Chung321e9ee2010-08-09 13:37:56 -0700243 }
244 }
245
246 @Override
Winson Chung321e9ee2010-08-09 13:37:56 -0700247 public boolean onTouchEvent(MotionEvent event) {
Winson Chungf0ea4d32011-06-06 14:27:16 -0700248 boolean result = super.onTouchEvent(event);
249 int count = getPageChildCount();
250 if (count > 0) {
251 // We only intercept the touch if we are tapping in empty space after the final row
252 View child = getChildOnPageAt(count - 1);
253 int bottom = child.getBottom();
254 int numRows = (int) Math.ceil((float) getPageChildCount() / getCellCountX());
255 if (numRows < getCellCountY()) {
256 // Add a little bit of buffer if there is room for another row
257 bottom += mCellHeight / 2;
258 }
259 result = result || (event.getY() < bottom);
260 }
261 return result;
Winson Chung321e9ee2010-08-09 13:37:56 -0700262 }
263
Winson Chung80baf5a2010-08-09 16:03:15 -0700264 public void enableCenteredContent(boolean enabled) {
Michael Jurka8245a862011-02-01 17:53:59 -0800265 mChildren.enableCenteredContent(enabled);
Winson Chung80baf5a2010-08-09 16:03:15 -0700266 }
267
Winson Chung321e9ee2010-08-09 13:37:56 -0700268 @Override
269 protected void setChildrenDrawingCacheEnabled(boolean enabled) {
Michael Jurka8245a862011-02-01 17:53:59 -0800270 mChildren.setChildrenDrawingCacheEnabled(enabled);
Winson Chung321e9ee2010-08-09 13:37:56 -0700271 }
272
273 public void setCellCount(int xCount, int yCount) {
274 mCellCountX = xCount;
275 mCellCountY = yCount;
276 requestLayout();
277 }
278
Winson Chungdf4b83d2010-10-20 17:49:27 -0700279 public void setGap(int widthGap, int heightGap) {
Winson Chung6032e7e2011-11-08 15:47:17 -0800280 mOriginalWidthGap = mWidthGap = widthGap;
281 mOriginalHeightGap = mHeightGap = heightGap;
Michael Jurka8245a862011-02-01 17:53:59 -0800282 mChildren.setGap(widthGap, heightGap);
Winson Chungdf4b83d2010-10-20 17:49:27 -0700283 }
284
Winson Chung80baf5a2010-08-09 16:03:15 -0700285 public int[] getCellCountForDimensions(int width, int height) {
286 // Always assume we're working with the smallest span to make sure we
287 // reserve enough space in both orientations
288 int smallerSize = Math.min(mCellWidth, mCellHeight);
289
290 // Always round up to next largest cell
291 int spanX = (width + smallerSize) / smallerSize;
292 int spanY = (height + smallerSize) / smallerSize;
293
294 return new int[] { spanX, spanY };
295 }
296
Winson Chung321e9ee2010-08-09 13:37:56 -0700297 /**
298 * Start dragging the specified child
299 *
300 * @param child The child that is being dragged
301 */
302 void onDragChild(View child) {
303 PagedViewCellLayout.LayoutParams lp = (PagedViewCellLayout.LayoutParams) child.getLayoutParams();
304 lp.isDragging = true;
305 }
306
Winson Chunge3193b92010-09-10 11:44:42 -0700307 /**
308 * Estimates the number of cells that the specified width would take up.
309 */
Winson Chung80baf5a2010-08-09 16:03:15 -0700310 public int estimateCellHSpan(int width) {
Winson Chung6032e7e2011-11-08 15:47:17 -0800311 // We don't show the next/previous pages any more, so we use the full width, minus the
312 // padding
Michael Jurka8b805b12012-04-18 14:23:14 -0700313 int availWidth = width - (getPaddingLeft() + getPaddingRight());
Winson Chungf0ea4d32011-06-06 14:27:16 -0700314
315 // We know that we have to fit N cells with N-1 width gaps, so we just juggle to solve for N
316 int n = Math.max(1, (availWidth + mWidthGap) / (mCellWidth + mWidthGap));
317
318 // We don't do anything fancy to determine if we squeeze another row in.
319 return n;
Winson Chung80baf5a2010-08-09 16:03:15 -0700320 }
Winson Chunge3193b92010-09-10 11:44:42 -0700321
322 /**
323 * Estimates the number of cells that the specified height would take up.
324 */
Winson Chung80baf5a2010-08-09 16:03:15 -0700325 public int estimateCellVSpan(int height) {
Winson Chungf0ea4d32011-06-06 14:27:16 -0700326 // The space for a page is the height - top padding (current page) - bottom padding (current
327 // page)
Michael Jurka8b805b12012-04-18 14:23:14 -0700328 int availHeight = height - (getPaddingTop() + getPaddingBottom());
Winson Chungf0ea4d32011-06-06 14:27:16 -0700329
330 // We know that we have to fit N cells with N-1 height gaps, so we juggle to solve for N
331 int n = Math.max(1, (availHeight + mHeightGap) / (mCellHeight + mHeightGap));
332
333 // We don't do anything fancy to determine if we squeeze another row in.
334 return n;
335 }
336
Winson Chung7d7541e2011-09-16 20:14:36 -0700337 /** Returns an estimated center position of the cell at the specified index */
338 public int[] estimateCellPosition(int x, int y) {
339 return new int[] {
Michael Jurka8b805b12012-04-18 14:23:14 -0700340 getPaddingLeft() + (x * mCellWidth) + (x * mWidthGap) + (mCellWidth / 2),
341 getPaddingTop() + (y * mCellHeight) + (y * mHeightGap) + (mCellHeight / 2)
Winson Chung7d7541e2011-09-16 20:14:36 -0700342 };
343 }
344
Winson Chungf0ea4d32011-06-06 14:27:16 -0700345 public void calculateCellCount(int width, int height, int maxCellCountX, int maxCellCountY) {
346 mCellCountX = Math.min(maxCellCountX, estimateCellHSpan(width));
347 mCellCountY = Math.min(maxCellCountY, estimateCellVSpan(height));
348 requestLayout();
Winson Chung80baf5a2010-08-09 16:03:15 -0700349 }
Winson Chunge3193b92010-09-10 11:44:42 -0700350
Winson Chung321e9ee2010-08-09 13:37:56 -0700351 @Override
352 public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
353 return new PagedViewCellLayout.LayoutParams(getContext(), attrs);
354 }
355
356 @Override
357 protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
358 return p instanceof PagedViewCellLayout.LayoutParams;
359 }
360
361 @Override
362 protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
363 return new PagedViewCellLayout.LayoutParams(p);
364 }
365
366 public static class LayoutParams extends ViewGroup.MarginLayoutParams {
367 /**
368 * Horizontal location of the item in the grid.
369 */
370 @ViewDebug.ExportedProperty
371 public int cellX;
372
373 /**
374 * Vertical location of the item in the grid.
375 */
376 @ViewDebug.ExportedProperty
377 public int cellY;
378
379 /**
380 * Number of cells spanned horizontally by the item.
381 */
382 @ViewDebug.ExportedProperty
383 public int cellHSpan;
384
385 /**
386 * Number of cells spanned vertically by the item.
387 */
388 @ViewDebug.ExportedProperty
389 public int cellVSpan;
390
391 /**
392 * Is this item currently being dragged
393 */
394 public boolean isDragging;
395
Winson Chung80baf5a2010-08-09 16:03:15 -0700396 // a data object that you can bind to this layout params
397 private Object mTag;
398
Winson Chung321e9ee2010-08-09 13:37:56 -0700399 // X coordinate of the view in the layout.
400 @ViewDebug.ExportedProperty
401 int x;
402 // Y coordinate of the view in the layout.
403 @ViewDebug.ExportedProperty
404 int y;
405
Winson Chung80baf5a2010-08-09 16:03:15 -0700406 public LayoutParams() {
407 super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
408 cellHSpan = 1;
409 cellVSpan = 1;
410 }
411
Winson Chung321e9ee2010-08-09 13:37:56 -0700412 public LayoutParams(Context c, AttributeSet attrs) {
413 super(c, attrs);
414 cellHSpan = 1;
415 cellVSpan = 1;
416 }
417
418 public LayoutParams(ViewGroup.LayoutParams source) {
419 super(source);
420 cellHSpan = 1;
421 cellVSpan = 1;
422 }
423
424 public LayoutParams(LayoutParams source) {
425 super(source);
426 this.cellX = source.cellX;
427 this.cellY = source.cellY;
428 this.cellHSpan = source.cellHSpan;
429 this.cellVSpan = source.cellVSpan;
430 }
431
432 public LayoutParams(int cellX, int cellY, int cellHSpan, int cellVSpan) {
433 super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
434 this.cellX = cellX;
435 this.cellY = cellY;
436 this.cellHSpan = cellHSpan;
437 this.cellVSpan = cellVSpan;
438 }
439
Daniel Sandlere4f98912013-06-25 15:13:26 -0400440 public void setup(Context context,
441 int cellWidth, int cellHeight, int widthGap, int heightGap,
442 int hStartPadding, int vStartPadding) {
Winson Chung321e9ee2010-08-09 13:37:56 -0700443
444 final int myCellHSpan = cellHSpan;
445 final int myCellVSpan = cellVSpan;
446 final int myCellX = cellX;
447 final int myCellY = cellY;
448
449 width = myCellHSpan * cellWidth + ((myCellHSpan - 1) * widthGap) -
450 leftMargin - rightMargin;
451 height = myCellVSpan * cellHeight + ((myCellVSpan - 1) * heightGap) -
452 topMargin - bottomMargin;
453
Daniel Sandlere4f98912013-06-25 15:13:26 -0400454 if (LauncherAppState.getInstance().isScreenLarge()) {
Winson Chung785d2eb2011-04-14 16:08:02 -0700455 x = hStartPadding + myCellX * (cellWidth + widthGap) + leftMargin;
456 y = vStartPadding + myCellY * (cellHeight + heightGap) + topMargin;
457 } else {
458 x = myCellX * (cellWidth + widthGap) + leftMargin;
459 y = myCellY * (cellHeight + heightGap) + topMargin;
460 }
Winson Chung321e9ee2010-08-09 13:37:56 -0700461 }
462
Winson Chung80baf5a2010-08-09 16:03:15 -0700463 public Object getTag() {
464 return mTag;
465 }
466
467 public void setTag(Object tag) {
468 mTag = tag;
469 }
470
Winson Chung321e9ee2010-08-09 13:37:56 -0700471 public String toString() {
Winson Chung80baf5a2010-08-09 16:03:15 -0700472 return "(" + this.cellX + ", " + this.cellY + ", " +
473 this.cellHSpan + ", " + this.cellVSpan + ")";
Winson Chung321e9ee2010-08-09 13:37:56 -0700474 }
475 }
Winson Chungc58497e2013-09-03 17:48:37 -0700476}