/*
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code 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. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package com.codename1.impl.blackberry;
import com.codename1.ui.Command;
import com.codename1.ui.Component;
import com.codename1.ui.Container;
import com.codename1.ui.Display;
import com.codename1.ui.Form;
import com.codename1.ui.PeerComponent;
import com.codename1.ui.TextArea;
import com.codename1.ui.events.ActionEvent;
import com.codename1.ui.plaf.UIManager;
import java.util.Vector;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.Characters;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.Keypad;
import net.rim.device.api.ui.component.Menu;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.MenuItem;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.EditField;
import net.rim.device.api.ui.container.FullScreen;
class BlackBerryCanvas extends FullScreen {
private boolean painted;
private Bitmap screen;
private Graphics globalGraphics;
BlackBerryImplementation impl;
private int screenWidth;
private int screenHeight;
private Vector commands;
static String debug = "";
private int lastNavigationDx;
private int lastNavigationDy;
boolean lastNavigationCharged;
/**
* If a peer component is the current focused component it should receive all
* events directly from the device
*/
Field eventTarget;
private Menu m;
public int getPreferredHeight() {
return net.rim.device.api.ui.Graphics.getScreenHeight();
}
public int getPreferredWidth() {
return net.rim.device.api.ui.Graphics.getScreenWidth();
}
protected BlackBerryCanvas(BlackBerryImplementation impl) {
super(new Manager(NO_VERTICAL_SCROLL | NO_VERTICAL_SCROLLBAR | NO_HORIZONTAL_SCROLL | NO_HORIZONTAL_SCROLLBAR) {
private void updateLayout(Component c, Field f) {
int x = c.getAbsoluteX() + c.getScrollX();
int y = c.getAbsoluteY() + c.getScrollY();
int w = c.getWidth();
int h = c.getHeight();
if(w < 1 || h < 1) {
w = f.getPreferredWidth();
h = f.getPreferredHeight();
}
setPositionChild(f, x, y);
layoutChild(f, w, h);
}
protected void sublayout(int width, int height) {
int n = getFieldCount();
Form currentForm = Display.getInstance().getCurrent();
for(int iter = 0 ; iter < n ; iter++) {
// find peer for field
Field f = getField(iter);
if(currentForm != null) {
PeerComponent p = findPeer(currentForm.getContentPane(), f);
if(p != null) {
updateLayout(p, f);
if(p.getPreferredH() < f.getHeight() || p.getPreferredW() < f.getWidth()) {
// blackberry reports a false size until the actual layout occurs we need to revalidate
p.invalidate();
}
} else {
Component cmp = currentForm.getFocused();
// we are now editing an edit field
if(cmp != null && cmp instanceof TextArea && cmp.hasFocus() && f instanceof EditField) {
updateLayout(cmp, f);
}
}
} else {
setPositionChild(f, 0, 0);
layoutChild(f, getPreferredWidth(), getPreferredHeight());
}
}
setExtent(width, height);
}
public int getPreferredHeight() {
return net.rim.device.api.ui.Graphics.getScreenHeight();
}
public int getPreferredWidth() {
return net.rim.device.api.ui.Graphics.getScreenWidth();
}
}, DEFAULT_MENU | NO_VERTICAL_SCROLL | NO_VERTICAL_SCROLLBAR | NO_HORIZONTAL_SCROLL | NO_HORIZONTAL_SCROLLBAR);
this.impl = impl;
// the alternative undeprecated API requires a signature
screenWidth = net.rim.device.api.ui.Graphics.getScreenWidth();
screenHeight = net.rim.device.api.ui.Graphics.getScreenHeight();
screen = new Bitmap(Bitmap.ROWWISE_16BIT_COLOR, screenWidth, screenHeight);
globalGraphics = new Graphics(screen);
}
static PeerComponent findPeer(Container c, Field f) {
PeerComponent p = (PeerComponent)BlackBerryImplementation.fieldComponentMap.get(f);
if(p != null) {
return p;
}
return findPeerImpl(c, f);
}
private static PeerComponent findPeerImpl(Container c, Field f) {
for(int iter = 0 ; iter < c.getComponentCount() ; iter++) {
Component current = c.getComponentAt(iter);
if(current instanceof PeerComponent) {
if(((PeerComponent)current).getNativePeer() == f) {
return (PeerComponent)current;
}
continue;
}
if(current instanceof Container) {
PeerComponent p = findPeerImpl((Container)current, f);
if(p != null) {
return p;
}
}
}
return null;
}
public void sublayout(int w, int h) {
//super.sublayout(w, h);
// the alternative undeprecated API requires a signature
if(net.rim.device.api.ui.Graphics.getScreenWidth() != screenWidth ||
net.rim.device.api.ui.Graphics.getScreenHeight() != screenHeight) {
screenWidth = net.rim.device.api.ui.Graphics.getScreenWidth();
screenHeight = net.rim.device.api.ui.Graphics.getScreenHeight();
if(screenWidth > 0 && screenHeight > 0) {
screen = new Bitmap(screenWidth, screenHeight);
globalGraphics = new Graphics(screen);
if(impl != null) {
impl.sizeChanged(screenWidth, screenHeight);
}
}
}
super.sublayout(w, h);
}
public void setNativeCommands(Vector commands) {
this.commands = commands;
}
public Menu getMenu(int val) {
if (Display.getInstance().getCommandBehavior() == Display.COMMAND_BEHAVIOR_NATIVE) {
m = new Menu();
if(commands != null){
for (int iter = 0; iter < commands.size(); iter++) {
final Command cmd = (Command) commands.elementAt(iter);
String txt = UIManager.getInstance().localize(cmd.getCommandName(), cmd.getCommandName());
MenuItem i = new MenuItem(txt, iter, iter) {
public void run() {
Display.getInstance().callSerially(new Runnable() {
public void run() {
impl.getCurrentForm().dispatchCommand(cmd, new ActionEvent(cmd));
}
});
}
};
m.add(i);
}
}
return m;
}
return super.getMenu(val);
}
public boolean onMenu(int i) {
if(Display.getInstance().getCommandBehavior() == Display.COMMAND_BEHAVIOR_NATIVE){
return super.onMenu(i);
}else{
return true;
}
}
protected void makeMenu(Menu menu, int instance) {
if(Display.getInstance().getCommandBehavior() == Display.COMMAND_BEHAVIOR_NATIVE){
menu = getMenu(instance);
super.makeMenu(menu, instance);
}
}
protected void onMenuDismissed(Menu arg0) {
if(Display.getInstance().getCommandBehavior() == Display.COMMAND_BEHAVIOR_NATIVE || impl.nativeEdit != null || eventTarget != null) {
super.onMenuDismissed(arg0);
}
}
protected void paintBackground(Graphics arg0) {
}
public void flush(int x, int y, int w, int h, UiApplication app) {
painted = false;
invalidate(x, y, w, h);
app.updateDisplay();
long time = System.currentTimeMillis();
while(!painted && app.isForeground() && !app.isPaintingSuspended()) {
Thread.yield();
// timeout on waiting to avoid freezing
// http://forums.java.net/jive/thread.jspa?messageID=393145
if(System.currentTimeMillis() - time > 150) {
return;
}
}
}
/*public void subpaint(Graphics g) {
paint(g);
}*/
/**
* Clips the RIM native graphics based on the component hierarchy within LWUIT
* so the native RIM component doesn't paint itself above other components such
* as the forms title.
*/
private int clipOnLWUITBounds(Component lwuitComponent, Graphics rimGraphics) {
int result = 0;
Component parent = lwuitComponent;
while (parent != null) {
int x = parent.getAbsoluteX() + parent.getScrollX();
int y = parent.getAbsoluteY() + parent.getScrollY();
rimGraphics.pushRegion(x, y, parent.getWidth(), parent.getHeight(), 0, 0);
rimGraphics.translate(-rimGraphics.getTranslateX(), -rimGraphics.getTranslateY());
parent = parent.getParent();
result++;
}
return result;
}
public void paint(Graphics g) {
int f = getFieldCount();
if(f > 0) {
g.drawBitmap(0, 0, getWidth(), getHeight(), screen, 0, 0);
Form currentForm = Display.getInstance().getCurrent();
for(int iter = 0 ; iter < f ; iter++) {
Field fld = getField(iter);
int pops = 0;
if(currentForm != null) {
PeerComponent p = findPeer(currentForm.getContentPane(), fld);
if(p != null) {
pops = clipOnLWUITBounds(p, g);
} else {
Component cmp = currentForm.getFocused();
// we are now editing an edit field
if(cmp != null && cmp instanceof TextArea && cmp.hasFocus() && fld instanceof EditField) {
pops = clipOnLWUITBounds(cmp, g);
int x = fld.getLeft();
int y = fld.getTop();
g.clear(x, y, Math.max(cmp.getWidth(), fld.getWidth()),
Math.max(cmp.getHeight(), fld.getHeight()));
}
}
}
paintChild(g, fld);
while(pops > 0) {
g.popContext();
pops--;
}
}
} else {
g.drawBitmap(0, 0, getWidth(), getHeight(), screen, 0, 0);
}
g.setColor(0);
g.drawText(debug, 0, 0);
painted = true;
}
public Graphics getGlobalGraphics() {
return globalGraphics;
}
protected boolean navigationClick(int status, int time) {
if(impl.nativeEdit != null || eventTarget != null) {
if(impl.nativeEdit != null) {
impl.finishEdit(false);
return true;
}
return super.navigationClick(status, time);
}
impl.keyPressed(BlackBerryImplementation.GAME_KEY_CODE_FIRE);
return true;
}
public void repeatLastNavigation() {
if(lastNavigationCharged) {
navigationMovement(lastNavigationDx, lastNavigationDy, 0, 0);
}
}
protected boolean navigationMovement(int dx, int dy, int status, int time) {
lastNavigationDx = dx;
lastNavigationDy = dy;
if(impl.nativeEdit != null || eventTarget != null) {
lastNavigationCharged = true;
if(dy > 0) {
if(impl.lightweightEdit.isSingleLineTextArea()) {
impl.finishEdit(false);
return true;
}
int pos = impl.nativeEdit.getCursorPosition();
if(impl.lightweightEdit.getText().length() - impl.lightweightEdit.getTextAt(impl.lightweightEdit.getLines() - 1).length() > pos) {
impl.finishEdit(false);
return true;
}
} else {
if(dy < 0) {
if(impl.lightweightEdit.isSingleLineTextArea()) {
impl.finishEdit(false);
return true;
}
int pos = impl.nativeEdit.getCursorPosition();
if(pos == 0 || impl.lightweightEdit.getTextAt(0).length() > pos) {
impl.finishEdit(false);
return true;
}
}
}
return super.navigationMovement(dx, dy, status, time);
}
lastNavigationCharged = false;
if (Math.abs(dx) > Math.abs(dy)) {
if (dx > 0) {
impl.keyPressed(BlackBerryImplementation.GAME_KEY_CODE_RIGHT);
impl.keyReleased(BlackBerryImplementation.GAME_KEY_CODE_RIGHT);
} else {
impl.keyPressed(BlackBerryImplementation.GAME_KEY_CODE_LEFT);
impl.keyReleased(BlackBerryImplementation.GAME_KEY_CODE_LEFT);
}
} else {
if (dy > 0) {
impl.keyPressed(BlackBerryImplementation.GAME_KEY_CODE_DOWN);
impl.keyReleased(BlackBerryImplementation.GAME_KEY_CODE_DOWN);
} else {
impl.keyPressed(BlackBerryImplementation.GAME_KEY_CODE_UP);
impl.keyReleased(BlackBerryImplementation.GAME_KEY_CODE_UP);
}
}
return true;
}
protected boolean navigationUnclick(int status, int time) {
if(impl.nativeEdit != null || eventTarget != null) {
return super.navigationUnclick(status, time);
}
impl.keyReleased(BlackBerryImplementation.GAME_KEY_CODE_FIRE);
return true;
}
protected boolean keyControl(char c, int status, int time) {
if(c == Characters.CONTROL_VOLUME_UP || c == Characters.CONTROL_VOLUME_DOWN) {
int i = MMAPIPlayer.getGlobalVolume();
if(i == -1) {
i = 70;
}
if(c == Characters.CONTROL_VOLUME_UP) {
MMAPIPlayer.setGlobalVolume(Math.min(100, i + 4));
} else {
MMAPIPlayer.setGlobalVolume(Math.max(0, i - 4));
}
if(BlackBerryImplementation.getVolumeListener() != null) {
BlackBerryImplementation.getVolumeListener().fireActionEvent(new ActionEvent(this, c));
return true;
}
}
return super.keyControl(c, status, time);
}
public boolean isTouchDevice() {
return false;
}
protected boolean keyStatus(int status, int time) {
if(impl.nativeEdit != null || eventTarget != null) {
return super.keyStatus(status, time);
}
return true;
}
protected boolean keyDown(int keyCode, int time) {
if(Keypad.key(keyCode) == Keypad.KEY_ESCAPE) {
if(isTouchDevice() && Display.getInstance().getDefaultVirtualKeyboard() != null){
if(Display.getInstance().getDefaultVirtualKeyboard().isVirtualKeyboardShowing()){
Display.getInstance().getDefaultVirtualKeyboard().showKeyboard(false);
}
}
// let the native editing code handle the escape
if(impl.nativeEdit != null) {
impl.finishEdit(false);
return true;
}
// prevent the browser component from "stealing" the escape key
impl.keyPressed(Keypad.KEY_ESCAPE);
return true;
}
if(Keypad.key(keyCode) == Keypad.KEY_END) {
if(BlackBerryImplementation.isMinimizeOnEnd()) {
Display.getInstance().minimizeApplication();
return true;
}
System.exit(0);
return true;
}
return super.keyDown(keyCode, time);
}
protected boolean keyChar(char c, int status, int time) {
if(impl.nativeEdit != null || eventTarget != null) {
return super.keyChar(c, status, time);
}
// HW_LAYOUT_ITUT: This means a standard phone keypad where the
// blackberry sends letters instead of numbers...
if(Keypad.getHardwareLayout() != 1230263636) {
impl.keyPressed(c);
impl.keyReleased(c);
} else {
int code = Keypad.getAltedChar(c);
//BlackBerryCanvas.debug = "K " + code + " c " + ((char)code) + " s " + status;
switch(code) {
case 0xa:
impl.keyPressed('#');
impl.keyReleased('#');
break;
// * is also the backspace key
//case 0x8:
// impl.keyPressed('*');
// impl.keyReleased('*');
// break;
default:
impl.keyPressed(code);
impl.keyReleased(code);
break;
}
}
return true;
}
protected boolean keyRepeat(int arg0, int arg1) {
return super.keyRepeat(arg0, arg1);
}
protected boolean keyUp(int keyCode, int time) {
if(Keypad.key(keyCode) == Keypad.KEY_ESCAPE) {
// prevent the browser component from "stealing" the escape key
impl.keyReleased(Keypad.KEY_ESCAPE);
return true;
}
if (Keypad.key(keyCode) == Keypad.KEY_MENU && Display.getInstance().getCommandBehavior() != Display.COMMAND_BEHAVIOR_NATIVE) {
if(impl.nativeEdit == null || eventTarget == null) {
impl.keyPressed(BlackBerryImplementation.MENU_SOFT_KEY);
impl.keyReleased(BlackBerryImplementation.MENU_SOFT_KEY);
return true;
}
}
return super.keyUp(keyCode, time);
}
public void setShowVirtualKeyboard(boolean show) {
}
public boolean isVirtualKeyboardShowingSupported() {
return false;
}
public boolean isMultiTouch() {
return false;
}
public boolean isClickTouchScreen() {
return false;
}
public boolean onClose() {
System.exit(0);
return true;
}
public void updateRIMLayout() {
super.updateLayout();
}
protected BlackBerryImplementation getImplementation(){
return impl;
}
protected void onDisplay() {
Display.getInstance().showNotify();
}
protected void onUndisplay() {
Display.getInstance().hideNotify();
}
protected void onExposed() {
EventLog.getInstance().logAlwaysEvent("onExposed");
if(impl.captureCallback != null){
impl.captureCallback.fireActionEvent(null);
impl.captureCallback = null;
}
}
protected void onObscured() {
EventLog.getInstance().logAlwaysEvent("onObscured");
}
}