Sunday, November 16, 2008

Custom Implicit List

If you have a few items to choose from, you may not need an LCDUI List instance. Below is a class that implements some methods of List, but have a custom drawing as it extends Canvas.
The main differences is that append method does not receive an Image parameter and the constructor receives only title as parameter.
On the next post we will add support for touch screen devices.
Attention: MIP 2.0 added title to Displayable. Some KVM implementations will draw the title even if a subclass overrides setTitle method. This will result on a double title drawing.


import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Graphics;

/**
* @author Telmo Mota - telmo.mota@gmail.com
*/
public class CustomImplicitList extends Canvas {

/**
* Command used to notify commandListener when number five or game action
* fire is pressed.
*/
public static final Command SELECT_COMMAND = new Command("",
Command.SCREEN, 0);

private CommandListener commandListener;

private String title;

private String[] items = new String[0];

private int selectedIndex = 0;

private Font font = Font.getDefaultFont();

/**
* Creates a new, empty List, specifying its title
*
* @param title
* the screen's title
*/
public CustomImplicitList(String title) {
this.title = title;
font = Font.getFont(font.getFace(), font.getSize(), Font.SIZE_LARGE);
}

/**
* @param item
*/
public void append(String item) {
this.insert(items.length, item);
}

/**
* @param index to insert the new item
* @param item to be inserted
*/
public void insert(int index, String item) {
String[] tmp = new String[items.length + 1];

System.arraycopy(items, 0, tmp, 0, index);
tmp[index] = item;
System.arraycopy(items, index, tmp, index + 1, items.length - index);
items = tmp;

// if font is already small, does not need to change it
if (font.getSize() != Font.SIZE_SMALL && this.font.stringWidth(item) >= getWidth()) {
int size = font.getSize();

if (size == Font.SIZE_LARGE) {
size = Font.SIZE_MEDIUM;
} else if (size == Font.SIZE_MEDIUM) {
size = Font.SIZE_SMALL;
}
font = Font.getFont(font.getFace(), font.getSize(), size);
}

if (this.isShown()) {
this.repaint();
}
}

/**
* @param index to be removed from items
*/
public void delete(int index) {
String[] tmp = new String[items.length - 1];

System.arraycopy(items, 0, tmp, 0, index);
if (index + 1 < items.length) {
System.arraycopy(items, index + 1, tmp, index, tmp.length - index);
}
items = tmp;
}

/**
* @return current selected item
*/
public int getSelectedIndex() {
return selectedIndex;
}

/**
* @return number of items
*/
public int size() {
return this.items.length;
}

/*
* @see javax.microedition.lcdui.Displayable#setCommandListener(javax.microedition.lcdui.CommandListener)
*/
public void setCommandListener(CommandListener l) {
super.setCommandListener(l);
this.commandListener = l;
}

/*
* @see
* javax.microedition.lcdui.Canvas#paint(javax.microedition.lcdui.Graphics)
*/
protected void paint(Graphics g) {
int height = this.getHeight();

g.setColor(0xffffff); // white
g.fillRect(0, 0, getWidth(), getHeight());

g.setColor(0); // black
g.setFont(font);

if (this.title != null) {
g.drawString(this.title, getWidth() / 2, 0, Graphics.HCENTER | Graphics.TOP);
height -= font.getHeight();
}

// vertically centered drawing
int y = (height - (this.items.length * font.getHeight())) / 2;

if (y < font.getHeight()) {
y = font.getHeight();
}

for (int i = 0; i < this.items.length; i++) {
g.drawString(this.items[i], getWidth() / 2, y, Graphics.HCENTER
| Graphics.TOP);
if (i == this.selectedIndex) {
g.drawRect(1, y, getWidth() - 3, font.getHeight());
}
y += font.getHeight();
// it was the last line that could be drawn
if (y + font.getHeight() > height) {
i = this.items.length;
}
}
}

/**
* Sets the selected state of an element. If elementNum is invalid, return
* silently.
*
* @param elementNum
* the index of the element, starting from zero
* @param selected
* the state of the element, where true means selected and false
* means not selected
*/
public void setSelectedIndex(int elementNum, boolean selected) {
if (elementNum < 0 || elementNum >= this.items.length) {
return;
}

if (selected) {
this.selectedIndex = elementNum;
} else {
this.selectedIndex = elementNum - 1;
if (this.selectedIndex < 0) {
this.selectedIndex = this.items.length - 1;
}
}
}

/**
* Gets the title of the Displayable. Returns null if there is no title.
*
* @return the title of the instance, or null if no title
*/
public String getTitle() {
return title;
}

/*
* @see javax.microedition.lcdui.Canvas#keyPressed(int)
*/
protected void keyPressed(int keyCode) {
int action = this.getGameAction(keyCode);

if (keyCode == Canvas.KEY_NUM8 || action == Canvas.DOWN) {
this.selectedIndex++;
if (this.selectedIndex >= this.items.length) {
this.selectedIndex = 0;
}
this.repaint();
} else if (keyCode == Canvas.KEY_NUM2 || action == Canvas.UP) {
this.selectedIndex--;
if (this.selectedIndex < 0) {
this.selectedIndex = this.items.length - 1;
}
this.repaint();
} else if (keyCode == Canvas.KEY_NUM5 || action == Canvas.FIRE) {
this.commandListener.commandAction(SELECT_COMMAND, this);
this.repaint();
}
}

}

No comments: