/*********************************************************************************
* TotalCross Software Development Kit *
* Copyright (C) 2000-2012 SuperWaba Ltda. *
* All Rights Reserved *
* *
* This library and virtual machine is distributed in the hope that it will *
* be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* *
* This file is covered by the GNU LESSER GENERAL PUBLIC LICENSE VERSION 3.0 *
* A copy of this license is located in file license.txt at the root of this *
* SDK or can be downloaded here: *
* http://www.gnu.org/licenses/lgpl-3.0.txt *
* *
*********************************************************************************/
package totalcross.ui;
import totalcross.sys.*;
import totalcross.ui.event.*;
import totalcross.ui.font.*;
import totalcross.ui.gfx.*;
/**
* Class that implements a Grid that each cell is a container.
* See the ImageBook sample, which also shows how to dynamically
* load and unload images. Here's a piece of it:
* <pre>
* add(gc = new GridContainer(GridContainer.HORIZONTAL_ORIENTATION),LEFT,TOP,FILL,FILL);
gc.setBackColor(Color.WHITE);
Flick f = gc.getFlick();
f.shortestFlick = 1000;
f.longestFlick = 6000;
gc.setPageSize(linhas,colunas);
gc.setRowsPerPage(linhasPorPagina);
Celula []cels = new Celula[TOTAL_ITEMS];
for (int i = 0; i < cels.length; i++)
cels[i] = new Celula(i);
gc.setCells(cels);
* </pre>
* @since TotalCross 1.53
*/
public class GridContainer extends Container
{
/** Defines a horizontal orientation scroll. */
public static final int HORIZONTAL_ORIENTATION = 0;
/** Defines a vertical orientation scroll. */
public static final int VERTICAL_ORIENTATION = 1;
private int orientation, cols, rows, rpp, pageCount;
/** The ScrollContainer used in this control. */
public ScrollContainer sc;
private Cell[] cells;
private ArrowButton btFirst, btLast;
private ArrowButton btPrev, btNext;
/** The container that has the page number and first/last arrows.
* Only works when orientation is horizontal, and is null otherwise. */
public NumericPagePosition pagepos;
/** A percentage that defines the heihgt of the arrow buttons. Defaults to 200 in penless devices, 100 otherwise.
*/
public int buttonsHeight = Settings.fingerTouch ? Control.isTablet ? 200 : 150 : 100;
/** Constructs a GridContainer with the given orientation
* @see #HORIZONTAL_ORIENTATION
* @see #VERTICAL_ORIENTATION
*/
public GridContainer(int orientation)
{
this.orientation = orientation;
sc = new ScrollContainer(orientation == HORIZONTAL_ORIENTATION, orientation == VERTICAL_ORIENTATION)
{
public int getScrollDistance()
{
return GridContainer.this.orientation == HORIZONTAL_ORIENTATION && cells != null && cells.length >= cols ? cells[cols-1].getX2()+1 : 0;
}
};
pagepos=new NumericPagePosition();
if (orientation == HORIZONTAL_ORIENTATION)
sc.flick.setPagePosition(pagepos);
}
/** Returns the flick attached to the ScrollContainer. */
public Flick getFlick()
{
return sc.flick;
}
/** A Grid's cell. All cells must extend this class so they can be added. */
public static class Cell extends Container
{
int inX,inY;
public Cell()
{
focusTraversable = true;
}
public void onEvent(Event e)
{
switch (e.type)
{
case PenEvent.PEN_DOWN:
{
PenEvent pe = (PenEvent)e;
inX = pe.x;
inY = pe.y;
break;
}
case PenEvent.PEN_UP:
{
PenEvent pe = (PenEvent)e;
int threeshold = width/4;
int dx = inX-pe.x; if (dx < 0) dx = -dx;
int dy = inY-pe.y; if (dy < 0) dy = -dy;
if (dx < threeshold && dy < threeshold && !hadParentScrolled())
postPressedEvent();
break;
}
}
}
}
public void onFontChanged()
{
sc.setFont(font);
}
private class FLArrowButton extends ArrowButton
{
public FLArrowButton(byte direction, int prefWH, int arrowColor)
{
super(direction, prefWH, arrowColor);
setBorder(BORDER_NONE);
}
public void onPaint(Graphics g)
{
super.onPaint(g);
g.backColor = arrowColor;
if (direction == Graphics.ARROW_LEFT)
g.fillRect(xx-2,yy,2,height);
else
g.fillRect(xx+fmH*buttonsHeight/100/2+1,yy,2,height);
}
}
public void initUI()
{
boolean isHoriz = orientation == HORIZONTAL_ORIENTATION;
int hh = fmH * buttonsHeight / 100;
if (isHoriz)
{
pagepos.setBackColor(Color.darker(backColor,16));
add(pagepos,CENTER,BOTTOM,PARENTSIZE+30,hh);
pagepos.setPosition(1);
sc.flick.setScrollDistance(width);
btFirst = new FLArrowButton(Graphics.ARROW_LEFT,hh/2,foreColor);
add(btFirst,LEFT,BOTTOM,PARENTSIZE+18,hh);
btPrev = new ArrowButton(Graphics.ARROW_LEFT,hh/2,foreColor);
btPrev.setBorder(Button.BORDER_NONE);
add(btPrev,AFTER,BOTTOM,PARENTSIZE+17,hh);
btPrev.autoRepeat = true;
add(sc,LEFT,TOP,FILL,FIT);
btLast = new FLArrowButton(Graphics.ARROW_RIGHT,hh/2,foreColor);
add(btLast,RIGHT,BOTTOM,PARENTSIZE+18,hh);
btNext = new ArrowButton(Graphics.ARROW_RIGHT,hh/2,foreColor);
btNext.setBorder(Button.BORDER_NONE);
add(btNext,BEFORE,BOTTOM,PARENTSIZE+17,hh);
btNext.autoRepeat = true;
sc.flick.forcedFlickDirection = orientation == HORIZONTAL_ORIENTATION ? Flick.HORIZONTAL_DIRECTION_ONLY : Flick.VERTICAL_DIRECTION_ONLY;
}
else
{
btFirst = new ArrowButton(Graphics.ARROW_UP,hh/2,foreColor);
btFirst.setBorder(Button.BORDER_NONE);
add(btFirst,LEFT,BOTTOM,PARENTSIZE+50,hh);
btFirst.setArrowSize(hh/2);
add(sc,LEFT,TOP,FILL,FIT);
btLast = new ArrowButton(Graphics.ARROW_DOWN,hh/2,foreColor);
btLast.setBorder(Button.BORDER_NONE);
add(btLast,RIGHT,BOTTOM,PARENTSIZE+50,hh);
btLast.setArrowSize(hh/2);
}
sc.flick.forcedFlickDirection = orientation == HORIZONTAL_ORIENTATION ? Flick.HORIZONTAL_DIRECTION_ONLY : Flick.VERTICAL_DIRECTION_ONLY;
}
/** Sets the rows per page. Changing this value changes the font size dynamically. */
public void setRowsPerPage(int rpp)
{
this.rpp = rpp;
}
/** Sets the page size in columns and rows. */
public void setPageSize(int cols, int rows)
{
this.cols = cols;
this.rows = rows;
}
/** Sets the cells of this GridContainer. Note that you cannot delete or add cells, only change the whole
* set of cells. You must call setRowsPerPage and/or setPageSize before calling this method.
*/
public void setCells(Cell[] cells)
{
sc.removeAll();
sc.setRect(KEEP,KEEP,KEEP,KEEP); // reset bag positions
if (rpp != 0)
setFont(Font.getFont(font.isBold(),Math.min(height,width)/rows/rpp));
this.cells = cells;
boolean singleCell = cols == 1 && rows == 1;
int percX = PARENTSIZE - cols;
int percY = PARENTSIZE - rows;
int px = LEFT, py = TOP;
int cr = cols*rows;
pageCount = cells.length / cr;
if ((cells.length % cr) != 0) pageCount++;
if (orientation == VERTICAL_ORIENTATION)
for (int z = 1; z <= cells.length; z++)
{
sc.add(cells[z-1],px,py,percX,percY);
if ((z%cols) != 0)
{px = AFTER; py = SAME;}
else
{px = LEFT; py = AFTER;}
}
else
{
pagepos.setCount(pageCount);
pagepos.setPosition(1);
Control last = null;
for (int z = 1, idx = cols-1; z <= cells.length; z++)
{
sc.add(cells[z-1],px,py,percX,percY,last);
last = null;
if (singleCell || (z%cols) != 0) // same row
{px = AFTER; py = SAME;}
else // change row
if (z < cr)
{px = LEFT; py = AFTER;}
else
{
last = cells[idx];
idx += cols;
}
}
// fill with spacers the rest of the columns if the last page has less than one column filled
int remains = cols - cells.length % cr;
if (remains > 0 && remains < cols)
for (int i = 0; i < remains; i++)
sc.add(new Spacer(0,0),AFTER,SAME,percX,1);
if (cells.length >= cols)
sc.flick.setScrollDistance(cells[cols-1].getX2()+1);
}
}
public void onEvent(Event e)
{
if (e.type == ControlEvent.PRESSED)
{
if (e.target == btFirst)
sc.scrollToPage(1);
else
if (e.target == btLast)
sc.scrollToPage(pageCount);
else
if (e.target == btPrev)
sc.scrollPage(true);
else
if (e.target == btNext)
sc.scrollPage(false);
}
}
public void onColorsChanged(boolean colorsChanged)
{
super.onColorsChanged(colorsChanged);
sc.setBackForeColors(getBackColor(),getForeColor());
}
}