package javax.microedition.lcdui;
import lejos.nxt.Button;
import lejos.nxt.ButtonListener;
import lejos.util.Timer;
import lejos.util.TimerListener;
/**
*
* @author Andre Nijholt
*/
public class Display {
private static final int TICKER_INTERVAL_MSEC = 100;
public static final int SCREEN_WIDTH = 100;
public static final int SCREEN_HEIGHT = 64;
public static final int CHAR_WIDTH = 6;
public static final int CHAR_HEIGHT = 8;
public static final int SCREEN_CHAR_WIDTH = SCREEN_WIDTH / CHAR_WIDTH;
public static final int SCREEN_CHAR_DEPTH = CHAR_HEIGHT;
private static Display display;
private Screen current;
private Screen alertBackup;
private int alertTimeout;
private Timer tickerTimer;
private int tickerOffset = SCREEN_WIDTH;
protected Graphics graphics;
private boolean quit;
private Display() {
graphics = new Graphics();
// We control when the screen gets updated explicitly
graphics.autoRefresh(false);
}
public static Display getDisplay() {
if (display == null) {
display = new Display();
}
return display;
}
public void setCurrent(Screen nextDisplayable) {
if (nextDisplayable != null) {
if (nextDisplayable instanceof Alert) {
// Only allow one level of alert
if (alertBackup == null)
alertBackup = current;
alertTimeout = (((Alert) nextDisplayable).getTimeout() == Alert.FOREVER) ? Alert.FOREVER
: ((int) System.currentTimeMillis()) + ((Alert) nextDisplayable).getTimeout();
}
if (current != null) {
current.hideNotify();
}
tickerOffset = SCREEN_WIDTH;
current = nextDisplayable;
current.showNotify();
current.repaint();
}
}
public void setCurrent(Alert alert, Screen nextDisplayable) {
if ((alert != null) && (nextDisplayable != null)) {
alertBackup = nextDisplayable;
if (current != null) {
current.hideNotify();
}
// Store timeout for alert screen
alertTimeout = (alert.getTimeout() == Alert.FOREVER) ? Alert.FOREVER
: ((int) System.currentTimeMillis()) + alert.getTimeout();
tickerOffset = SCREEN_WIDTH;
current = alert;
current.showNotify();
current.repaint();
}
}
public Displayable getCurrent() {
return current;
}
/**
* Start displaying the installed menus
*
* @param polling true to poll for button updates (recommended)
*/
public void show(boolean polling) {
if (!polling) {
// Use non-polling implementation
showUsingListeners();
return;
}
int btnPressed;
int tsTickerUpdate = (int) System.currentTimeMillis();
while (!quit) {
// Wait for button release
while (!quit && (Button.readButtons() > 0)) {
Thread.yield();
}
// Wait for button pressed and handle main timer checks
while (!quit && (Button.readButtons() == 0)) {
if (msecPassed(tsTickerUpdate)) {
int tickerLen = updateTicker(tickerOffset);
if (tickerLen > 0) {
tickerOffset--;
if (tickerOffset < -tickerLen) {
tickerOffset = SCREEN_WIDTH;
}
}
tsTickerUpdate = (int) System.currentTimeMillis() + TICKER_INTERVAL_MSEC;
}
if ((current != null) && (current instanceof Alert)
&& (alertTimeout != Alert.FOREVER) && msecPassed(alertTimeout)) {
// Hide alert screen and replace backup without notify
current.hideNotify();
current = alertBackup;
alertBackup = null;
}
// Handle repaint requests from outside
update();
Thread.yield();
}
// Check if menu to handle
if (current == null) {
continue;
}
// Debounce button press
try {
Thread.sleep(20);
} catch (InterruptedException e) {}
// Handle debounced button press
btnPressed = Button.readButtons();
if (btnPressed == 1) {
// ENTER button pressed
if (current instanceof Alert) {
// Hide alert screen and replace backup without notify
Screen saved = current;
current.keyPressed(Displayable.KEY_ENTER);
// Make sure that we are still current!
if (saved == current)
{
current.hideNotify();
current = alertBackup;
alertBackup = null;
}
} else {
current.keyPressed(Displayable.KEY_ENTER);
}
update();
} else if (btnPressed == 2) {
// LEFT button pressed
current.keyPressed(Displayable.KEY_LEFT);
update();
} else if (btnPressed == 4) {
// RIGHT button pressed
current.keyPressed(Displayable.KEY_RIGHT);
update();
} else if (btnPressed == 8) {
// ESCAPE button pressed
current.keyPressed(Displayable.KEY_BACK);
update();
}
}
// End application
System.exit(0);
}
public void quit() {
quit = true;
}
private void showUsingListeners() {
Button.ENTER.addButtonListener(new ButtonListener() {
public void buttonReleased (Button b) {}
public void buttonPressed (Button b) {
if (current != null) {
if (current instanceof Alert) {
// Hide alert screen and replace backup without notify
Screen saved = current;
current.keyPressed(Displayable.KEY_ENTER);
// Make sure that we are still current!
if (saved == current)
{
current.hideNotify();
current = alertBackup;
alertBackup = null;
}
} else {
current.keyPressed(Displayable.KEY_ENTER);
}
update();
}
}
});
Button.ESCAPE.addButtonListener(new ButtonListener() {
public void buttonReleased (Button b) {}
public void buttonPressed (Button b) {
if (current != null) {
current.keyPressed(Displayable.KEY_BACK);
update();
}
}
});
Button.LEFT.addButtonListener(new ButtonListener() {
public void buttonReleased (Button b) {}
public void buttonPressed (Button b) {
if (current != null) {
current.keyPressed(Displayable.KEY_LEFT);
update();
}
}
});
Button.RIGHT.addButtonListener(new ButtonListener() {
public void buttonReleased (Button b) {}
public void buttonPressed (Button b) {
if (current != null) {
current.keyPressed(Displayable.KEY_RIGHT);
update();
}
}
});
tickerTimer = new Timer(TICKER_INTERVAL_MSEC, new TimerListener() {
public void timedOut() {
int tickerLen = updateTicker(tickerOffset);
if (tickerLen > 0) {
tickerOffset--;
if (tickerOffset < -tickerLen) {
tickerOffset = SCREEN_WIDTH;
}
}
}
});
tickerTimer.start();
// Start update timer task
new Timer(50, new TimerListener() {
public void timedOut() {
if ((current != null) && (current instanceof Alert)
&& (alertTimeout != Alert.FOREVER) && msecPassed(alertTimeout)) {
// Hide alert screen and replace backup without notify
current.hideNotify();
current = alertBackup;
alertBackup = null;
}
if (quit) {
System.exit(0);
}
update();
}
}).start();
}
private synchronized void update() {
if (current.getPaintRequest()) {
graphics.clear();
updateTicker(tickerOffset);
current.paint(graphics);
current.clearPaintRequest();
graphics.refresh();
}
}
private int updateTicker(int offset) {
Ticker ticker = current.getTicker();
if (ticker != null) {
int old = graphics.getColor();
graphics.setColor(Graphics.WHITE);
graphics.fillRect(0, 0, SCREEN_WIDTH, CHAR_HEIGHT);
graphics.setColor(old);
graphics.drawString(ticker.getString(), offset, 0);
/*
int tickerLen = ticker.getString().length();
for (int i = 0; i < SCREEN_CHAR_WIDTH; i++) {
if ((i >= offset) && ((i - offset) < tickerLen)) {
graphics.drawChar(ticker.getString().charAt(i - offset),
i * Display.CHAR_WIDTH, 0, false);
} else {
graphics.drawChar(' ', i * Display.CHAR_WIDTH, 0, false);
}
}*/
graphics.refresh();
return ticker.getString().length()*CHAR_WIDTH;
}
return 0;
}
/**
* Returns true if the given timestamp passed
*
* @param ts Timestamp in milliseconds
* @return true if ts already passed, otherwise false
*/
private boolean msecPassed(int ts) {
return (((int) System.currentTimeMillis() - ts) > 0);
}
}