/* Copyright (c) 2008 Bluendo S.r.L.
* See about.html for details about license.
*
* $Id: UIScreen.java 1601 2009-06-19 14:09:03Z luca $
*/
package it.yup.ui;
import java.util.Enumeration;
import java.util.Vector;
import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Font;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
/**
* Fornisce uno schermo che mostra una lista di items generici e espone
* funzionalita' di menu. Ogni item puo' avere una azione associata alla
* pressione del tasto di selezione.<br>
*
* Il Menu viene mostrato alla pressione del tasto del menu (tipicamente quello
* destro), E' una lista di voci che viene mostrata in un overlay che non copre
* tutto lo schermo (la dimensione dipende dalla dimensione dello schermo e
* dalla dimensione del font; si pua' aggiungere che se la scritta sfora la
* larghezza del menu e la voce e' selezionata ogni X (=1 o 2) secondi il menu
* viene ridipinto.<br>
*
*/
public class UIScreen extends UIMenu implements UIIContainer {
/** il menu di questo screen */
private UIMenu menu;
private boolean freezed = false;
/*
* UIScreen needs a fresh repaint (meaning even the background must be completly
* repainted) when changing from one screen to another.
*/
boolean firstPaint = false;
/**
* The {@link UICanvas} owning the screen.
*/
private UICanvas canvas = null;
/**
* The list of the popup for this screen.
*/
protected Vector popupList;
/**
* The screen title
*/
public UILabel titleLabel = new UILabel("");
protected Image la = UICanvas.getUIImage("/icons/lag.png");
protected Image ra = UICanvas.getUIImage("/icons/rag.png");
protected UISeparator headerSep = new UISeparator(1);
protected UIVLayout headerLayout = null;
/**
* The footer elements
*/
protected UIHLayout footer = new UIHLayout(2);
public UILabel footerLeft = new UILabel("");
public UILabel footerRight = new UILabel("");
/**
* The graphics in which the screen is painted
*
*/
private Graphics graphics;
private Vector paintedItems = new Vector(10);
/** Called to notify that the {@link UIScreen} has become visible */
public void showNotify() {
}
/** Called to notify that the {@link UIScreen} has become invisible */
public void hideNotify() {
}
/**
* Constructor, each screen is associated to the Canvas
*/
public UIScreen() {
super("Screen");
borderSize = 0;
int imgHeight = la.getHeight();
this.headerLayout = new UIVLayout(2, imgHeight);
headerSep.setFg_color(0);
headerLayout.insert(headerSep, 0, 1, UILayout.CONSTRAINT_PIXELS);
headerLayout.insert(titleLabel, 1, imgHeight,
UILayout.CONSTRAINT_PIXELS);
titleLabel.setScreen(this);
titleLabel.setBg_color(UIConfig.header_bg);
titleLabel.setFg_color(UIConfig.menu_title);
titleLabel.setFont(UIConfig.font_title);
titleLabel.setAnchorPoint(Graphics.HCENTER);
this.setItemList(new Vector());
this.popupList = new Vector();
this.canvas = UICanvas.getInstance();
selectedIndex = -1;
this.width = UICanvas.getInstance().getWidth();
this.height = UICanvas.getInstance().getClipHeight();
footer.setGroup(false);
footer.setFocusable(false);
footer.insert(footerLeft, 0, 50, UILayout.CONSTRAINT_PERCENTUAL);
footer.insert(footerRight, 1, 50, UILayout.CONSTRAINT_PERCENTUAL);
this.footerLeft.setScreen(this);
this.footerRight.setScreen(this);
footerLeft.setBg_color(UIConfig.header_bg);
footerLeft.setFg_color(UIConfig.menu_title);
footerLeft.setFont(UIConfig.font_title);
footerLeft.setAnchorPoint(Graphics.LEFT);
footerRight.setBg_color(UIConfig.header_bg);
footerRight.setFg_color(UIConfig.menu_title);
footerRight.setFont(UIConfig.font_title);
footerRight.setAnchorPoint(Graphics.RIGHT);
this.screen = this;
}
/**
* Adds the passed item to the bottom of the itemList.
*
* @param ui
* The item to add.
* @return The position which the item has been added in.
*/
public int append(UIItem ui) {
getItemList().addElement(ui);
ui.setScreen(this);
ui.setContainer(this);
ui.setDirty(true);
this.askRepaint();
return getItemList().size() - 1;
}
/**
* Adds a popUp to the popup vector.
*
* @param popUp
* The item to add.
*/
public void addPopup(UIMenu popUp) {
this.popupList.addElement(popUp);
popUp.setDirty(true);
popUp.setScreen(this);
this.askRepaint();
}
/**
* Remove a popUp from the popup vector.
*
* @param popUp
* The item to remove.
*/
public void removePopup(UIMenu popUp) {
if (popUp != null && this.popupList.contains(popUp)) {
popUp.setOpenedState(false);
popUp.setSubmenu(null);
this.popupList.removeElement(popUp);
this.invalidateArea(popUp.getAbsoluteX(), popUp.getAbsoluteY(),
popUp.getAbsoluteX() + popUp.getWidth(), popUp
.getAbsoluteY()
+ popUp.getHeight(this.graphics));
}
this.askRepaint();
}
public void removeAllPopups() {
for (Enumeration en = popupList.elements(); en.hasMoreElements();) {
UIMenu uim = (UIMenu) en.nextElement();
uim.setOpenedState(false);
uim.setSubmenu(null);
this.invalidateArea(uim.getAbsoluteX(), uim.getAbsoluteY(), uim
.getAbsoluteX()
+ uim.getWidth(), uim.getAbsoluteY()
+ uim.getHeight(this.graphics));
}
this.popupList.removeAllElements();
this.askRepaint();
}
public boolean popupIsPresent(UIMenu popUp) {
return this.popupList.contains(popUp);
}
/**
* Adds the passed item at the pos-th position of the itemList.
*
* @param pos
* The position which the item has to be added in.
* @param ui
* The item to add.
*/
public void insert(int pos, UIItem ui) {
if (pos < 0 || pos >= getItemList().size()) { throw new ArrayIndexOutOfBoundsException(
"Invalid menu pos: " + getItemList() + ", "
+ getItemList().size()); }
int oldSelectedIndex = this.getSelectedIndex();
getItemList().insertElementAt(ui, pos);
if (pos <= oldSelectedIndex) this.setSelectedIndex(++oldSelectedIndex);
ui.setScreen(this);
ui.setContainer(this);
ui.setDirty(true);
for (int i = pos; i < getItemList().size(); i++) {
((UIItem) getItemList().elementAt(i)).setDirty(true);
}
this.askRepaint();
}
/**
* Removes the item at the pos-th position of the itemList.
*
* @param pos
* The position from which the item has to be removed.
* @return returns the removed Item.
*/
public UIItem remove(int pos) {
UIItem ui = super.remove(pos);
for (int i = pos; i < getItemList().size(); i++) {
((UIItem) getItemList().elementAt(i)).setDirty(true);
}
if (selectedIndex >= pos) selectedIndex--;
if (firstVisibleIndex > this.getItemList().size() - 1) firstVisibleIndex = 0;
if (lastVisibleIndex > this.getItemList().size() - 1) lastVisibleIndex = this
.getItemList().size() - 1;
this.askRepaint();
return ui;
}
/**
* Removes the passed item from the itemList.
*
* @param ui
* The item to remove.
*/
public boolean remove(UIItem ui) {
int tempIndex = this.indexOf(ui);
if (tempIndex >= 0) {
this.remove(tempIndex);
return true;
}
return false;
}
/**
* Removes all the items.
*/
public void removeAll() {
super.removeAll();
firstVisibleIndex = 0;
lastVisibleIndex = 0;
this.askRepaint();
}
/**
* Replace the item at the passed inedx with the newly furnished one. If
* {@code pos} is not a valid value for the itemList an
* {@link ArrayIndexOutOfBoundsException} is thrown.
*
* @param pos
* The item position
* @param ui
* The {@link UIItem} to replace
* @return the removed item
*/
public UIItem replace(int pos, UIItem ui) {
UIItem posth = super.replace(pos, ui);
ui.setScreen(this);
ui.setContainer(this);
this.askRepaint();
return posth;
}
public void replace(UIItem oldItem, UIItem newItem) {
int oldPos = this.indexOf(oldItem);
this.replace(oldPos, newItem);
}
/**
* Swaps two object in the list
*
* @param firstIndex
* @param secondIndex
* @return
*/
public void swap(int firstIndex, int secondIndex) {
if (firstIndex >= this.getItemList().size()
|| secondIndex >= this.getItemList().size()) throw new ArrayIndexOutOfBoundsException(
"Invalid itemList pos: " + firstIndex + " " + secondIndex
+ ", " + getItemList().size());
Object temp = getItemList().elementAt(firstIndex);
getItemList().setElementAt(getItemList().elementAt(secondIndex),
firstIndex);
getItemList().setElementAt(temp, secondIndex);
UIItem dirtyItem = (UIItem) getItemList().elementAt(firstIndex);
dirtyItem.setDirty(true);
UIItem dirtyItem2 = (UIItem) getItemList().elementAt(secondIndex);
dirtyItem2.setDirty(true);
this.askRepaint();
}
/**
* Set this screen's menu. If the menu is {@code null} the menu is disabled.
*
* @param _menu
* the screen's menu
*/
public void setMenu(UIMenu _menu) {
menu = _menu;
if (menu != null) menu.setScreen(this);
}
/**
* @return The screen menu.
*/
public UIMenu getMenu() {
return menu;
}
/*
* Raised when a drag is made
*/
public void startDrag(UIItem draggedItem) {
}
/*
* Raised when a drag is made
*/
public void endDrag() {
}
/**
* <p>
* Handle the key pressure.
* </p>
* Dispatches the key pressure to the menu or to the item depending on the
* state.
*
* @param key
* The pressed key.
*
* @return <code>true</code> if the screen will keep the selection
*/
public boolean keyPressed(int key) {
/* the part below has been introduced to handle correctly the
* synchronization between the "UI" thread and the others that access the UI
*
* Notes:
* 1) paintCount is synchronized and used here and in askRepaint: if
* paintCount is greather than zero the askRepaint does not repaint
* 2) if key is one of the "action" key (fire or menu keys) this thread do not lock
* because they will call askRepaint later
*
*
*/
// boolean needLocking = true;
// if (key == UICanvas.MENU_RIGHT || key == UICanvas.MENU_LEFT
// || canvas.getGameAction(key) == Canvas.FIRE) {
// needLocking = false;
// }
// synchronized (this) {
// if (painting == false)
// painting = true;
// else
// paintBooked = true;
// }
// if (needLocking) UICanvas.lock();
boolean selectionKept = false;
try {
if (this.popupList.size() > 0) {
handleMenuKey((UIMenu) this.popupList.elementAt(this.popupList
.size() - 1), key);
selectionKept = true;
// if the key is propagated to a popup or a menu it can can change
// the popup size and hence force a repaint
this.firstPaint = true;
} else if (this.menu != null && this.menu.isOpenedState()) {
handleMenuKey(menu, key);
selectionKept = true;
// if the key is propagated to a popup or a menu it can can change
// the popup size and hence force a repaint
this.firstPaint = true;
} else {
if (key == UICanvas.MENU_RIGHT) {
/* open menu */
if (menu != null) {
int menuSize = menu.getItemList().size();
UIMenu contMenu = null;
UIItem selItem = null;
if (selectedIndex >= 0
&& selectedIndex < this.itemList.size()) {
selItem = ((UIItem) this.getItemList().elementAt(
selectedIndex)).getSelectedItem();
}
if (selItem != null) contMenu = selItem.getSubmenu();
else if (selectedIndex >= 0
&& selectedIndex < this.itemList.size()) {
contMenu = ((UIItem) this.getItemList().elementAt(
selectedIndex)).getSubmenu();
}
if (menuSize == 2 && contMenu == null) {
this.menuAction(menu, (UIItem) menu.getItemList()
.elementAt(0));
} else if (menuSize > 1) {
menu.setOpenedState(true);
this.askRepaint();
} else if (menuSize == 1) {
this.menuAction(menu, (UIItem) menu.getItemList()
.elementAt(0));
}
}
selectionKept = true;
} else if (key == UICanvas.MENU_LEFT) {
if (selectedIndex >= 0
&& selectedIndex < this.itemList.size()) {
// A "contextual menu" has been asked
UIItem selItem = ((UIItem) this.getItemList()
.elementAt(selectedIndex)).getSelectedItem();
// An UIitem like UICombobox can have no selectedItem but a subMenu
UIMenu contMenu = null;
if (selItem != null) contMenu = selItem.getSubmenu();
else
contMenu = ((UIItem) this.getItemList().elementAt(
selectedIndex)).getSubmenu();
if (this.selectedIndex >= 0 && contMenu != null) {
// if menu has 0 width centers it on the screen
if (contMenu.getWidth() == 0) contMenu.width = UICanvas
.getInstance().getWidth()
- contMenu.getAbsoluteX() * 2;
if (contMenu.getItemList().size() > 1) this
.addPopup(contMenu);
else if (contMenu.getItemList().size() == 1) menuAction(
contMenu, (UIItem) contMenu.getItemList()
.elementAt(0));
} else {
// second items of normal menu has been asked
int menuSize = menu.getItemList().size();
if (menuSize == 2) {
this.menuAction(menu, (UIItem) menu
.getItemList().elementAt(1));
}
}
} else {
// second items of normal menu has been asked
int menuSize = menu.getItemList().size();
if (menuSize == 2) {
this.menuAction(menu, (UIItem) menu.getItemList()
.elementAt(1));
}
}
}
// first let the item receive the keyPressure
if (this.selectedIndex >= 0) selectionKept = ((UIItem) this
.getItemList().elementAt(this.selectedIndex))
.keyPressed(key);
int ka = canvas.getGameAction(key);
int newSelectedIndex = 0;
// then take the "movement"
if (selectionKept == false) {
/* no menu opened, handle key normally */
switch (ka) {
case Canvas.UP:
if (selectedIndex == 0) {
/* first item selected, can't go up further */
break;
}
newSelectedIndex = 0;
if (selectedIndex >= 0) {
newSelectedIndex = selectedIndex - 1;
}
newSelectedIndex = traverseFocusable(
newSelectedIndex, false);
if (newSelectedIndex >= 0
&& newSelectedIndex < this.getItemList()
.size()) {
UIItem selectedItem = ((UIItem) this
.getItemList().elementAt(
newSelectedIndex));
if (selectedItem.isFocusable()) {
if (selectedIndex >= 0) {
((UIItem) this.getItemList().elementAt(
selectedIndex))
.setSelected(false);
}
selectedIndex = newSelectedIndex;
((UIItem) this.getItemList().elementAt(
selectedIndex)).setSelected(true);
} else {
this.firstVisibleIndex = 0;
for (int i = 0; i <= this.lastVisibleIndex; i++) {
((UIItem) this.getItemList().elementAt(
i)).setDirty(true);
}
}
}
this.askRepaint();
break;
case Canvas.DOWN:
if (selectedIndex == this.getItemList().size() - 1) {
/* last item selected, can't go down further */
break;
}
newSelectedIndex = 0;
if (selectedIndex >= 0) {
/* move selection down */
newSelectedIndex = selectedIndex + 1;
}
newSelectedIndex = traverseFocusable(
newSelectedIndex, true);
if (newSelectedIndex >= 0
&& newSelectedIndex < this.getItemList()
.size()) {
if (((UIItem) this.getItemList().elementAt(
newSelectedIndex)).isFocusable()) {
if (selectedIndex >= 0) {
((UIItem) this.getItemList().elementAt(
selectedIndex))
.setSelected(false);
}
selectedIndex = newSelectedIndex;
((UIItem) this.getItemList().elementAt(
selectedIndex)).setSelected(true);
} else if (lastVisibleIndex < this
.getItemList().size() - 1) {
int gapHeight = 0;
for (int i = this.lastVisibleIndex + 1; i < this
.getItemList().size(); i++)
gapHeight += ((UIItem) this
.getItemList().elementAt(i))
.getHeight(this.graphics);
do {
UIItem ithElem = ((UIItem) this
.getItemList().elementAt(
firstVisibleIndex));
gapHeight -= ithElem
.getHeight(this.graphics);
this.firstVisibleIndex++;
} while (gapHeight > 0);
for (int i = firstVisibleIndex; i < this
.getItemList().size(); i++) {
((UIItem) this.getItemList().elementAt(
i)).setDirty(true);
}
}
}
this.askRepaint();
break;
default:
break;
}
}
// then raise the "fire" event
if (ka == Canvas.FIRE && this.selectedIndex >= 0) {
UIItem selectedItem = ((UIItem) this.getItemList()
.elementAt(selectedIndex)).getSelectedItem();
if (selectedItem != null) this.itemAction(selectedItem);
selectionKept = true;
}
// #mdebug
//@ System.out.println("moved: " + firstVisibleIndex + "/"
//@ + lastVisibleIndex + "/" + selectedIndex);
// #enddebug
}
} catch (Exception e) {
// #mdebug
//@ System.out.println("In keyPressed");
//@ e.printStackTrace();
// #enddebug
}
// if (needLocking) UICanvas.unlock();
// synchronized (this) {
// painting = false;
// }
//this.askRepaint();
return selectionKept;
}
void handleMenuKey(UIMenu openMenu, int key) {
Object[] oldPopups = new Object[popupList.size()];
this.popupList.copyInto(oldPopups);
if (key == UICanvas.MENU_RIGHT
|| canvas.getGameAction(key) == Canvas.FIRE) {
/* select, close menu */
} else if (key == UICanvas.MENU_LEFT) {
/* cancel, close menu */
openMenu.setOpenedState(false);
if (openMenu != null) {
// the menu was here -> invalidate all:
int x1 = openMenu.getAbsoluteX();
int y1 = openMenu.getAbsoluteY();
int x2 = x1 + openMenu.getWidth();
int y2 = y1 + openMenu.getHeight(this.graphics);
this.invalidateArea(x1, y1, x2, y2);
}
if (openMenu.getParentMenu() != null) {
openMenu.getParentMenu().setSubmenu(null);
}
this.removePopup((UIMenu) openMenu);
this.askRepaint();
return;
}
int ga = canvas.getGameAction(key);
UIItem um = openMenu.keyPressed(key, ga);
if (um != null) {
// if a UIMenuItem has been selected and it has not
// a submenu i need to close the menu
if (um.getSubmenu() == null) {
if (openMenu.isAutoClose()) {
openMenu.setOpenedState(false);
// the menu was here -> invalidate all:
int menuY = openMenu.getAbsoluteY();
int cumulativeHeight = this.headerLayout
.getHeight(this.graphics);
for (int i = this.firstVisibleIndex; i < this.getItemList()
.size(); i++) {
UIItem ith = (UIItem) this.getItemList().elementAt(i);
cumulativeHeight += ith.getHeight(this.graphics);
if (cumulativeHeight >= menuY) {
ith.setDirty(true);
}
}
if (this.menu != null) {
this.menu.setOpenedState(false);
this.menu.setSubmenu(null);
}
}
this.askRepaint();
}
// first close the menu and then complete the action
if ((key == UICanvas.MENU_RIGHT || ga == UICanvas.FIRE)) {
this.menuAction(openMenu, um);
}
if (um.getSubmenu() == null) {
if (openMenu.isAutoClose()) {
// we cannot use: this.removeAllPopups();
// because if a menu has been added meanwhile (for example in
// response
// to a keypression) it is removed suddenly !!!
for (int i = 0; i < oldPopups.length; i++) {
this.removePopup((UIMenu) oldPopups[i]);
}
}
this.askRepaint();
}
}
}
private boolean paintBooked = false;
private boolean painting = false;
/**
* Used by items and menus to ask the containing screen a repaint.
*/
protected boolean askRepaint() {
boolean paintEnable = false;
synchronized (this) {
// #mdebug
//@ System.out.println("painting: " + painting);
// #enddebug
if (painting == false) {
paintEnable = true;
painting = true;
} else
paintBooked = true;
}
if (paintEnable) {
try {
this.canvas.askRepaint(this);
} catch (Exception e) {
// #mdebug
//@ System.out.println("in screen painting");
//@ e.printStackTrace();
// #enddebug
}
// someone else in the meanwhile
boolean paintForce = false;
synchronized (this) {
painting = false;
if (paintBooked) {
paintBooked = false;
paintForce = true;
}
}
if (paintForce) {
this.askRepaint();
}
}
return true;
}
/**
* Paints the screen on the canvas graphics; in case the subclasses override
* this method they *MUST* provide to call super.paint (...); .
*
* @param g
* The graphics on which to paint.
*/
public boolean paint(Graphics g) {
changed = false;
this.graphics = g;
// in many devices the height may vary during execution
this.height = UICanvas.getInstance().getClipHeight();
int footerHeight = UIConfig.font_title.getHeight() + 2;
int headerHeight = (headerLayout != null) ? headerLayout.getHeight(g)
: 0;
/* draw title */
Font cfont = g.getFont();
// String oldFont = cfont.getFace() + "-" + cfont.getHeight() + "-"
// + cfont.getSize() + "-" + cfont.getStyle() + " ";
if (headerLayout != null && headerLayout.isDirty()) {
int oldColor = g.getColor();
g.setColor(UIConfig.header_bg);
g.fillRect(0, 0, g.getClipWidth(), headerHeight);
g.drawImage(la, 0, 0, Graphics.LEFT | Graphics.TOP);
g.translate(la.getWidth(), 0);
int titleWidth = g.getClipWidth() - la.getWidth() - ra.getWidth();
headerLayout.paint0(g, titleWidth, headerHeight);
g.translate(titleWidth, 0);
g.drawImage(ra, 0, 0, Graphics.LEFT | Graphics.TOP);
g.translate(-g.getTranslateX(), 0);
g.setColor(oldColor);
changed = true;
}
/* calculate clip area for content */
int canvasHeight = this.canvas.getClipHeight();
// subtract footer height
canvasHeight -= footerHeight;
int canvasWidth = this.canvas.getWidth();
// subtract header height (if present)
g.setClip(0, headerHeight, canvasWidth, canvasHeight - headerHeight);
g.translate(0, headerHeight);
// #mdebug
//@ System.out.println("paint0: " + canvasWidth + "/"
//@ + (canvasHeight - headerHeight) + "/" + g.getClipHeight() + "/"
//@ + g.getTranslateY());
// #enddebug
// a trick used to avoid painting of screen when a popup is opened
/* draw menu if opened */
boolean aMenuIsOpened = false;
if ((this.menu != null && this.menu.isOpenedState())
|| this.popupList.size() > 0) {
aMenuIsOpened = true;
}
if (aMenuIsOpened == false || firstPaint) {
firstPaint = false;
this.paint0(g, canvasWidth, canvasHeight - headerHeight);
this.removePaintedItem(this);
// clean the gap
if (this.lastVisibleIndex == this.getItemList().size() - 1) {
g.setColor(getBg_color() >= 0 ? getBg_color()
: UIConfig.bg_color);
int yGapHeight = canvasHeight - headerHeight;
int usedHeight = 0;
for (int i = firstVisibleIndex; i <= lastVisibleIndex; i++) {
UIItem ui = (UIItem) getItemList().elementAt(i);
usedHeight += ui.getHeight(g);
}
g.translate(-g.getTranslateX(), headerHeight + usedHeight
- g.getTranslateY());
int gap = 1 + yGapHeight - usedHeight;
if (this.getNeedScrollbar() == false) {
g.fillRect(1, 0, canvasWidth, gap);
} else {
g.fillRect(1, 0, canvasWidth - UIConfig.scrollbarWidth - 1,
gap);
}
// if the gap is filled menu and popups can be dirty
// and must be redrawn
if (menu != null) {
menu.setDirty(true);
}
for (Enumeration en = popupList.elements(); en
.hasMoreElements();) {
UIMenu ithPopup = (UIMenu) en.nextElement();
ithPopup.setDirty(true);
}
changed = true;
}
}
/* draw menu if opened */
if (this.menu != null && this.menu.isOpenedState()
&& this.menu.isDirty()) {
// force repaint of all the menu items
this.menu.setDirty(true);
//int x0 = 17;
int x0 = 29;
int y0 = canvasHeight / 2;
//int x1 = canvasWidth - x0 + 5;
int x1 = canvasWidth;
//int y1 = canvasHeight - 2;
int y1 = canvasHeight;
// g.setClip(x0, y0, x1, y1); XXX: TODO
int translatedX = g.getTranslateX();
int translatedY = g.getTranslateY();
g.translate(-translatedX, -translatedY);
g
.setClip(0, headerHeight, canvasWidth, canvasHeight
- headerHeight);
// I choose a maximum height for the menus
int menuHeight = menu.getHeight(g);
if (menuHeight > y0) menuHeight = y0;
g.translate(x0, y1 - menuHeight);
menu.setAbsoluteX(x0);
menu.setAbsoluteY(y1 - menuHeight);
menu.paint0(g, x1 - x0, y1 - y0);
changed = true;
}
// first draw the popup list
boolean hasPopup = false;
for (Enumeration en = popupList.elements(); en.hasMoreElements();) {
hasPopup = true;
changed = true;
int translatedX = g.getTranslateX();
int translatedY = g.getTranslateY();
UIMenu ithPopup = (UIMenu) en.nextElement();
g.translate(-translatedX, -translatedY);
// move the popup in order to have it on the screen
if (ithPopup.getAbsoluteY() < headerHeight) {
ithPopup.setAbsoluteY(headerHeight);
}
// subtract footer height and header for the available area
int availableHeight = this.canvas.getClipHeight() - footerHeight
- ithPopup.getAbsoluteY();
// set a clip for the popup in order to avoid overprinting
// header and footer;
g
.setClip(0, headerHeight, canvasWidth, canvasHeight
- headerHeight);
g.translate(ithPopup.getAbsoluteX(), ithPopup.getAbsoluteY());
// if a popup is dirty must be redrawn and
// all the subsequent
// if (ithPopup.isDirty() && i < (this.popupList.size() - 1)) {
// ((UIMenu) this.popupList.elementAt(i + 1)).setDirty(true);
// }
if (ithPopup.isDirty()) {
// force repaint of all the menu items
ithPopup.setDirty(true);
ithPopup.paint0(g, ithPopup.width, availableHeight);
ithPopup.setOpenedState(true);
}
}
// draw the border (just in case something has overwritten it)
g.translate(-g.getTranslateX(), headerHeight - g.getTranslateY());
g.setClip(0, 0, canvas.getWidth(), canvas.getClipHeight());
g.setColor(0x223377);
g.drawRect(0, 0, canvasWidth - 1, canvasHeight - headerHeight);
g.translate(-g.getTranslateX(), -g.getTranslateY());
/* footer height */
g
.translate(0 - g.getTranslateX(), canvasHeight + 1
- g.getTranslateY());
/* draw menu buttons - LEFT */
String left = "";
if (hasPopup || (menu != null && menu.isOpenedState())) {
if (hasPopup) {
left = ((UIMenu) this.popupList
.elementAt(this.popupList.size() - 1)).cancelMenuString;
}
if ((menu != null && menu.isOpenedState())) {
left = menu.cancelMenuString;
}
} else if (selectedIndex >= 0) {
UIItem selItem = ((UIItem) this.getItemList().elementAt(
selectedIndex)).getSelectedItem();
UIMenu contMenu = null;
if (selItem != null) contMenu = selItem.getSubmenu();
else
contMenu = ((UIItem) this.getItemList()
.elementAt(selectedIndex)).getSubmenu();
if (contMenu != null) {
if (contMenu.getItemList().size() == 1) {
UIItem firstItem = (UIItem) contMenu.getItemList()
.elementAt(0);
if (firstItem instanceof UILabel) left = ((UILabel) firstItem)
.getText();
else
left = UIConfig.optionsString;
} else
left = UIConfig.optionsString;
}
}
if (left.compareTo(this.footerLeft.getText()) != 0) {
this.footerLeft.setText(left);
changed = true;
}
String right = "";
if (menu != null && !menu.isOpenedState() && !hasPopup) {
if (menu.getItemList().size() == 1) right = ((UILabel) menu
.getItemList().elementAt(0)).getText();
else if (menu.getItemList().size() == 2 && left.length() == 0) {
right = ((UILabel) menu.getItemList().elementAt(0)).getText();
left = ((UILabel) menu.getItemList().elementAt(1)).getText();
} else
right = UIConfig.menuString;
} else if ((menu != null && menu.isOpenedState()) || hasPopup) {
if (hasPopup) {
right = ((UIMenu) this.popupList.elementAt(this.popupList
.size() - 1)).selectMenuString;
}
if ((menu != null && menu.isOpenedState())) {
right = menu.selectMenuString;
}
}
if (right.compareTo(this.footerRight.getText()) != 0) {
this.footerRight.setText(right);
changed = true;
}
if (left.compareTo(this.footerLeft.getText()) != 0) {
this.footerLeft.setText(left);
changed = true;
}
if (footer.isDirty()) {
footer.paint0(g, canvasWidth, footer.getHeight(g));
g.setColor(UIConfig.header_fg);
g.drawLine(canvasWidth / 2, 0, canvasWidth / 2, footerHeight);
}
// #mdebug
//@ System.out.println("screenPaint done: " + g.getClipWidth() + "/"
//@ + g.getClipHeight() + "/" + g.getTranslateX() + "/"
//@ + g.getTranslateY());
// #enddebug
g.setFont(cfont);
return changed;
}
/**
* @return This screen's title
*/
public String getTitle() {
return this.titleLabel.getText();
}
/**
* Sets this screen's title
*
* @param title
* the screen title
*/
public void setTitle(String title) {
this.titleLabel.setText(title);
}
public UICanvas getCanvas() {
return canvas;
}
/*
* Invalidates the portion of the screen between (0,0) and (w,h)
*/
public void invalidate(int w, int h) {
int cumulativeHeight = 0;
// remove footer height
int fh = this.headerLayout.getHeight(this.graphics);
h = h - fh;
// reset the Items
this.firstVisibleIndex = 0;
for (Enumeration en = getItemList().elements(); en.hasMoreElements();) {
UIItem ithItem = (UIItem) en.nextElement();
cumulativeHeight += ithItem.getHeight(this.graphics);
ithItem.setDirty(true);
}
// reset the popups
for (Enumeration en = popupList.elements(); en.hasMoreElements();) {
UIMenu ithMenu = (UIMenu) en.nextElement();
int ithMenuHeight = ithMenu.getAbsoluteY()
+ ithMenu.getHeight(this.graphics);
if (ithMenuHeight > h) {
ithMenu.setAbsoluteY(ithMenu.getAbsoluteY()
- (ithMenuHeight - h));
}
int ithMenuWidth = ithMenu.getAbsoluteX() + ithMenu.getWidth();
if (ithMenuWidth > w) {
ithMenu.setAbsoluteX(ithMenu.getAbsoluteX()
- (ithMenuWidth - w));
}
if (ithMenu.getAbsoluteX() < w || ithMenu.getAbsoluteY() < h) {
ithMenu.setDirty(true);
}
}
this.headerLayout.setDirty(true);
this.footer.setDirty(true);
}
/**
* This method is called each time a {@link UIMenuItem} of a {@link UIMenu}
* receives the pressure of a FIRE. The subclasses of screen SHOULD override
* this method in order to couple an action to the pressure of an action
* key.
*
* @param menu
* The selected Menu
* @param item
* The {@link UIMenuItem} that received the key pressure
*/
public void menuAction(UIMenu menu, UIItem item) {
}
/**
* This method is called each time a {@link UIItem} of this {@link UIScreen}
* receives the pressure of a FIRE. The subclasses of screen SHOULD override
* this method in order to couple an action to the pressure of an action
* key.
*
* @param item
* The {@link UIItem} that received the key pressure
*/
public void itemAction(UIItem item) {
}
/**
* @param graphics
* the graphics to set
*/
public void setGraphics(Graphics graphics) {
this.graphics = graphics;
}
/**
* @return the graphics
*/
public Graphics getGraphics() {
return graphics;
}
/**
* @return Return true if this {@link UIScreen} is freezed
*/
synchronized public boolean isFreezed() {
return freezed;
}
/**
* @param Freezes
* or Unfreezes this {@link UIScreen}.
*/
synchronized public void setFreezed(boolean freezed) {
this.freezed = freezed;
}
/**
* All the menuItems and popups that intersects this area are set as dirty
*/
public void invalidateArea(int x1, int y1, int x2, int y2) {
// first check if it intersects any item in itemList
int cumulativeHeight = this.headerLayout.getHeight(this.graphics);
for (int i = this.firstVisibleIndex; i < this.getItemList().size(); i++) {
UIItem ith = (UIItem) this.getItemList().elementAt(i);
int xa = 0, xb = this.width;
int ya = cumulativeHeight;
int yb = cumulativeHeight + ith.getHeight(this.graphics);
if (intersect(new int[] { x1, y1, x2, y2 }, new int[] { xa, ya, xb,
yb })) {
ith.setDirty(true);
}
cumulativeHeight = yb;
}
// then the popup
for (Enumeration en = popupList.elements(); en.hasMoreElements();) {
UIMenu ithMenu = (UIMenu) en.nextElement();
int xa = ithMenu.getAbsoluteX(), xb = xa + ithMenu.getWidth();
int ya = ithMenu.getAbsoluteY();
int yb = ya + ithMenu.getHeight(this.graphics);
if (intersect(new int[] { x1, y1, x2, y2 }, new int[] { xa, ya, xb,
yb })) {
ithMenu.setDirty(true);
}
}
// and then the menu if opened
if (this.menu != null && this.menu.isOpenedState()) {
int xa = this.menu.getAbsoluteX(), xb = xa + this.menu.getWidth();
int ya = this.menu.getAbsoluteY();
int yb = ya + this.menu.getHeight(this.graphics);
if (intersect(new int[] { x1, y1, x2, y2 }, new int[] { xa, ya, xb,
yb })) {
this.menu.setDirty(true);
}
}
}
private boolean intersect(int[] recta, int[] rectb) {
int x1 = recta[0];
int y1 = recta[1];
int x2 = recta[2];
int y2 = recta[3];
int xa = rectb[0];
int ya = rectb[1];
int xb = rectb[2];
int yb = rectb[3];
if ((xb < x1) || (x2 < xa) || (yb < y1) || (y2 < ya)) return false;
return true;
}
public void invalidatePopups(UIMenu drawnMenu, int x1, int y1, int x2,
int y2) {
// reset the clips in order to invalidate correctely
// all the objects in the screen
Graphics g = this.graphics;
int originalClipWidth = g.getClipWidth();
int originalClipHeight = g.getClipHeight();
int originalClipX = g.getClipX();
int originalClipY = g.getClipY();
int w = UICanvas.getInstance().getWidth();
int h = UICanvas.getInstance().getClipHeight();
g.setClip(0, 0, w, h);
int cumulativeHeight = this.headerLayout.getHeight(g);
for (int i = this.firstVisibleIndex; i < itemList.size(); i++) {
UIItem ith = (UIItem) this.getItemList().elementAt(i);
int xa = 0, xb = this.width;
int ya = cumulativeHeight;
int yb = cumulativeHeight + ith.getHeight(this.graphics);
if (intersect(new int[] { x1, y1, x2, y2 }, new int[] { xa, ya, xb,
yb })) {
ith.setDirty(true);
}
cumulativeHeight = yb;
}
if (this.menu != null && this.menu != drawnMenu
&& this.menu.isOpenedState()) {
int xa = this.menu.getAbsoluteX(), xb = xa + this.menu.getWidth();
int ya = this.menu.getAbsoluteY();
int yb = ya + this.menu.getHeight(this.graphics);
if (intersect(new int[] { x1, y1, x2, y2 }, new int[] { xa, ya, xb,
yb })) {
this.menu.setDirty(true);
}
}
// then the popup
for (Enumeration en = popupList.elements(); en.hasMoreElements();) {
UIMenu ithMenu = (UIMenu) en.nextElement();
if (ithMenu == drawnMenu) continue;
int xa = ithMenu.getAbsoluteX(), xb = xa + ithMenu.getWidth();
int ya = ithMenu.getAbsoluteY();
int yb = ya + ithMenu.getHeight(this.graphics);
if (intersect(new int[] { x1, y1, x2, y2 }, new int[] { xa, ya, xb,
yb })) {
ithMenu.setDirty(true);
}
}
g.setClip(originalClipX, originalClipY, originalClipWidth,
originalClipHeight);
}
public void setDirty(boolean dirty) {
super.setDirty(dirty);
for (Enumeration en = popupList.elements(); en.hasMoreElements();) {
UIItem ithItem = (UIItem) en.nextElement();
ithItem.setDirty(dirty);
}
if (this.menu != null) this.menu.setDirty(dirty);
this.headerLayout.setDirty(true);
this.footer.setDirty(true);
this.paintedItems.removeAllElements();
}
public void setSelectedIndex(int selectedIndex) {
super.setSelectedIndex(selectedIndex);
if (selectedIndex > lastVisibleIndex) {
// forcing it to be the last visible to avoid useless
// redraw
lastVisibleIndex = selectedIndex;
}
}
/*
* The keyRepeated is usually handled at the sam manner
* moving the screen / control up and down
*/
public void keyRepeated(int key) {
int ga = UICanvas.getInstance().getGameAction(key);
switch (ga) {
case Canvas.DOWN:
case Canvas.UP: {
this.setFreezed(true);
for (int i = 0; i < 5; i++) {
this.keyPressed(key);
}
this.setFreezed(false);
this.askRepaint();
}
}
}
/*
* The coordinates plus height and width of each item in this screen
*
*/
public void addPaintedItem(UIItem item) {
removePaintedItem(item);
paintedItems.insertElementAt(item, 0);
}
/*
* Remove a painted item from screen paintItems
*
*/
public void removePaintedItem(UIItem item) {
paintedItems.removeElement(item);
}
public Vector getPaintedItems() {
return paintedItems;
}
public void setPopupList(Vector popupList) {
this.popupList = popupList;
}
public Vector getPopupList() {
return popupList;
}
}