/*
Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
и других спецификаций для функционирования компактных приложений на языке
Java (мидлетов) в среде программного обеспечения Малик Эмулятор.
Copyright © 2016, 2019 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package javax.microedition.lcdui;
import malik.emulator.media.graphics.*;
public abstract class Displayable extends Object
{
private static class TickerScrolling extends Object
implements Runnable
{
private static class Event extends Object
implements Runnable
{
private boolean queued;
private Displayable screen;
public Event()
{
}
public void run()
{
Displayable screen;
Ticker ticker = (screen = this.screen) != null ? screen.ticker : null;
if(ticker != null && screen.isReallyShown() && screen.getMode() == MODE_WITH_TICKER)
{
ticker.scroll();
screen.callSeriallyPaintScreen(TICKER);
}
this.queued = false;
this.screen = null;
}
public void set(Displayable screen)
{
if(queued) return;
this.queued = true;
this.screen = screen;
screen.callSerially(this);
}
}
private boolean terminated;
public TickerScrolling()
{
}
public void run()
{
Event tickerScrollingEvent = new Event();
Display display = MIDletProxy.getInstance().getEmulatorScreen();
for(Displayable screen; ; )
{
waitEvent();
if(terminated) break;
if((screen = display.getShownScreen()) == null) continue;
while(display.isShown(screen) && screen.ticker != null)
{
tickerScrollingEvent.set(screen);
try
{
Thread.sleep((long) Display.getMinimumPeriod());
}
catch(InterruptedException e)
{
e.printRealStackTrace();
}
}
}
}
public synchronized void update()
{
notify();
}
public synchronized void terminate()
{
terminated = true;
notify();
}
private synchronized void waitEvent()
{
for(; ; )
{
try
{
wait();
break;
}
catch(InterruptedException e)
{
e.printRealStackTrace();
}
}
}
}
static final int ALL = -1;
static final int TITLE = 0x01;
static final int TICKER = 0x02;
static final int CLIENT = 0x04;
static final int COMMANDS = 0x08;
static final int GUI_ELEMENT_TITLE = 0;
static final int GUI_ELEMENT_TICKER = 1;
static final int GUI_ELEMENT_CLIENT = 2;
static final int GUI_ELEMENT_COMMANDS = 3;
static final int MODE_WITHOUT_TICKER = 0;
static final int MODE_WITH_TICKER = 1;
static final int MODE_FULL_SCREEN = 2;
private static final int MENU_SPIN_WIDTH = 16;
private static final int MENU_SPIN_HEIGHT = 16;
private static final int MENU_MAX_ELEMENTS = 7;
private static final int MENU_OUTER_MARGIN = 4;
private static final int MENU_INNER_MARGIN = 6;
private static final int[] DEVICE_KEYS_FOR_COMMANDS;
private static final int[] COMMAND_TYPES_FOR_SOFT2;
private static final Command[] MENU_PANEL_COMMANDS;
private static final Command MENU;
private static final Command BACK;
private static final Command SELECT;
private static final TickerScrolling TICKER_SCROLLING;
static
{
Command menu = new Command("Меню", Command.SCREEN, 0);
Command back = new Command("Назад", Command.BACK, 0);
Command select = new Command("Выбрать", Command.OK, 0);
DEVICE_KEYS_FOR_COMMANDS = new int[] {
MIDletProxy.DEVICE_KEY_SOFT1,
MIDletProxy.DEVICE_KEY_SELECT,
MIDletProxy.DEVICE_KEY_SOFT2
};
COMMAND_TYPES_FOR_SOFT2 = new int[] {
Command.BACK, Command.CANCEL,
Command.STOP, Command.EXIT
};
MENU_PANEL_COMMANDS = new Command[] {
null, select, back
};
MENU = menu;
BACK = back;
SELECT = select;
TICKER_SCROLLING = new TickerScrolling();
}
static void tickerStart()
{
(new Thread(TICKER_SCROLLING, "Прокрутка бегущих строк")).start();
}
static void tickerStop()
{
TICKER_SCROLLING.terminate();
}
static void tickerUpdate()
{
TICKER_SCROLLING.update();
}
static Command[] addCommand(Command[] list, int count, Command command)
{
int c;
if(command == null)
{
return null;
}
if(list == null || (c = list.length) == 0)
{
count = 0;
list = new Command[3];
} else
{
for(int i = count; i-- > 0; )
{
if(list[i] == command)
{
return null;
}
}
if(count == c)
{
Array.copy(list, 0, list = new Command[(c << 1) + 1], 0, c);
}
}
list[count] = command;
return list;
}
static Command[] removeCommand(Command[] list, int count, Command command)
{
int i;
int c;
if(command == null)
{
return null;
}
for(i = list == null || list.length <= 0 ? 0 : count; i-- > 0; )
{
if(list[i] != command)
{
continue;
}
if((c = --count - i) > 0)
{
Array.copy(list, i + 1, list, i, c);
}
list[count] = null;
return list;
}
return null;
}
static Command[] concatCommands(Command[] list1, Command[] list2)
{
int len1 = list1 == null ? 0 : list1.length;
int len2 = list2 == null ? 0 : list2.length;
Command[] result;
if(len1 <= 0)
{
return list2;
}
if(len2 <= 0)
{
return list1;
}
result = new Command[len1 + len2];
Array.copy(list1, 0, result, 0, len1);
Array.copy(list2, 0, result, len1, len2);
return result;
}
static String truncate(String text, Font font, int width)
{
int i;
int len;
int pos;
char[] c;
if(text == null || (len = text.length()) <= 0)
{
return "";
}
if(width < 0)
{
return text;
}
if(font == null)
{
font = Font.getDefaultFont();
}
for(pos = len, i = 0; i < len; i++)
{
if(text.charAt(i) < 32)
{
pos = i;
break;
}
}
if(pos < len)
{
text.getChars(0, pos, c = new char[len = pos + 1], 0);
c[pos] = '…';
}
else if(font.stringWidth(text) > width)
{
(c = text.toCharArray())[len - 1] = '…';
}
else
{
return text;
}
while(len > 1 && font.charsWidth(c, 0, len) > width)
{
c[--len - 1] = '…';
}
return (new String(c, 0, len)).intern();
}
private static Command findCommand(CommandEnumeration enumeration, int type, Command ignore)
{
Command result = null;
for(int priority = Integer.MAX_VALUE, i = enumeration.getCommandsCount(); i-- > 0; )
{
int p;
Command command;
if((command = enumeration.getCommand(i)) != null && command != ignore &&
command.getRealType() == type && (p = command.getRealPriority()) <= priority)
{
result = command;
priority = p;
}
}
return result;
}
private class SizeChangedEvent extends Object
implements Runnable
{
public SizeChangedEvent()
{
}
public void run()
{
Displayable screen;
(screen = Displayable.this).staySizeChanged = false;
if(!screen.isReallyShown())
{
screen.needSizeChanged = true;
return;
}
screen.needSizeChanged = false;
screen.onSizeChanged(screen.getClientWidth(), screen.getClientHeight());
}
}
private class CommandActionEvent extends Object
implements Runnable
{
private Command command;
public CommandActionEvent(Command command)
{
this.command = command;
}
public void run()
{
(Displayable.this).onCommandAction(command);
}
}
private final class CommandEnumerator extends Object
implements CommandEnumeration
{
public CommandEnumerator()
{
}
public int getCommandsCount()
{
return (Displayable.this).commandsCount;
}
public Command getCommand(int index)
{
Displayable screen;
if(index < 0 || index >= (screen = Displayable.this).commandsCount)
{
throw new IndexOutOfBoundsException("Displayable.getCommands: " +
"индекс выходит из диапазона.");
}
return screen.commandsInScreen[index];
}
public Command getDefaultCommand()
{
return (Displayable.this).defaultCommand;
}
public Object getMonitor()
{
return (Displayable.this).getCommandsMonitor();
}
}
private boolean system;
private boolean needSizeChanged;
private boolean staySizeChanged;
private boolean menuOpened;
private int menuFirstIndex;
private int menuSelectedIndex;
private int mode;
private int repaintElements;
private int commandFocused;
private int commandPressed;
private int commandsCount;
private Command[] commandsInScreen;
private Command[] commandsOnPanel;
private Command[] commandsOnMenu;
private Command defaultCommand;
private CommandListener listener;
private CommandEnumeration commandsEnumeration;
private Ticker ticker;
private String title;
private Object lock;
Displayable(boolean system, boolean fullScreenMode, String title, Ticker ticker,
Command[] commands, Command defaultCommand, CommandListener listener)
{
int len;
Command[] c;
if((len = commands == (c = null) ? 0 : commands.length) > 0)
{
Array.copy(commands, 0, c = new Command[len], 0, len);
for(int i = defaultCommand != null ? -1 : 0; i < len; i++)
{
Command cmd;
if((cmd = i < 0 ? defaultCommand : c[i]) == null && i >= 0)
{
throw new NullPointerException("Displayable: " +
"один из элементов аргумента commands равен нулевой ссылке.");
}
for(int j = i + 1; j < len; j++)
{
if(c[j] == cmd)
{
throw new IllegalArgumentException("Displayable: " +
"аргумент commands содержит равные элементы или элементы, " +
"равные аргументу defaultCommand.");
}
}
}
}
this.system = system;
this.needSizeChanged = true;
this.mode = fullScreenMode && listener == null ? MODE_FULL_SCREEN :
ticker != null ? MODE_WITH_TICKER : MODE_WITHOUT_TICKER;
this.commandFocused = -1;
this.commandPressed = -1;
this.commandsCount = len;
this.commandsInScreen = c;
this.commandsOnPanel = new Command[3];
this.defaultCommand = defaultCommand;
this.listener = listener;
this.commandsEnumeration = this.new CommandEnumerator();
this.ticker = ticker;
this.title = title;
this.lock = new Object();
placeCommandsNeedRepaint();
}
public void addCommand(Command command)
{
boolean changed;
if(command == null)
{
throw new NullPointerException("Displayable.addCommand: " +
"аргумент command равен нулевой ссылке.");
}
changed = false;
synchronized(lock)
{
int len;
Command[] c;
if(command != defaultCommand && (c = addCommand(commandsInScreen,
len = commandsCount, command)) != null)
{
commandsCount = len + 1;
commandsInScreen = c;
changed = true;
}
}
if(changed)
{
updateCommands();
}
}
public void removeCommand(Command command)
{
boolean changed;
if(command == null)
{
return;
}
changed = false;
synchronized(lock)
{
int len;
Command[] c;
if(command == defaultCommand)
{
defaultCommand = null;
changed = true;
}
else if((c = removeCommand(commandsInScreen,
len = commandsCount, command)) != null)
{
commandsCount = len - 1;
commandsInScreen = c;
changed = true;
}
}
if(changed)
{
updateCommands();
}
}
public void setCommandListener(CommandListener listener)
{
boolean changedmode;
this.listener = listener;
if(listener == null) return;
synchronized(lock)
{
changedmode = mode != (mode = ticker != null ? MODE_WITH_TICKER : MODE_WITHOUT_TICKER);
}
if(changedmode)
{
tickerUpdate();
callSeriallySizeChanged();
callSeriallyMenuClose();
}
}
public void setTitle(String title)
{
boolean changed = false;
synchronized(lock)
{
String current = this.title;
if(title == null || title.length() <= 0 ? current != null && current.length() > 0 :
current == null || current.length() <= 0 || !current.equals(title))
{
this.title = title;
changed = true;
}
}
if(changed)
{
callSeriallyPaintScreen(TITLE);
}
}
public void setTicker(Ticker ticker)
{
boolean changed = false;
boolean changedmode = false;
synchronized(lock)
{
if(ticker != this.ticker)
{
int currmode;
this.ticker = ticker;
changedmode = (currmode = mode) != MODE_FULL_SCREEN && currmode != (mode =
ticker != null ? MODE_WITH_TICKER : MODE_WITHOUT_TICKER);
changed = true;
}
}
if(changed)
{
tickerUpdate();
if(changedmode)
{
callSeriallySizeChanged();
}
callSeriallyPaintScreen(ticker != null ? changedmode ? TICKER | CLIENT : TICKER : CLIENT);
}
}
public boolean isShown()
{
return MIDletProxy.getInstance().getEmulatorScreen().isShown(this);
}
public int getWidth()
{
return getClientWidth();
}
public int getHeight()
{
return getClientHeight();
}
public String getTitle()
{
return title;
}
public Ticker getTicker()
{
return ticker;
}
public final boolean isSystem()
{
return system;
}
protected void sizeChanged(int width, int height)
{
}
abstract void paint(Graphics render);
void paintTitle(Graphics render, int width, int height, String title)
{
render.setColor(RasterCanvas.getSystemColor(0x09));
render.drawElementOfGUI(6, 1, 0, 0, 0, width, height);
render.drawString(title, 2, 2, 0);
}
void paintTicker(Graphics render, int width, int height, Ticker ticker)
{
render.setColor(RasterCanvas.getSystemColor(0x29));
render.drawElementOfGUI(13, 0, 0, 0, 0, width, height);
render.drawString(ticker.getDisplayedText(), ticker.getPosition(), 2, 0);
}
void paintClient(Graphics render, int width, int height,
int clipLeft, int clipTop, int clipWidth, int clipHeight)
{
int x;
int y;
Display display;
Graphics clientRender;
x = (display = MIDletProxy.getInstance().getEmulatorScreen()).getGUIElementLeft(this, GUI_ELEMENT_CLIENT);
y = mode == MODE_FULL_SCREEN ?
display.getGUIElementTop(this, GUI_ELEMENT_CLIENT) :
display.getGUIElementTop(this, GUI_ELEMENT_TITLE) +
display.getGUIElementHeight(this, GUI_ELEMENT_TITLE);
render.drawElementOfGUI(6, 5, 0, x - render.getTranslateX(), y - render.getTranslateY(),
display.getWidth() - x, display.getHeight() - y);
(clientRender = getClientContext()).reset();
clientRender.translate(getClientLeft(), getClientTop());
clientRender.setClip(clipLeft, clipTop, clipWidth, clipHeight);
paint(clientRender);
}
void paintCommands(Graphics render, int width, int height,
Command[] commands, int pressedIndex, Font defaultCommandFont)
{
int x;
int y;
int q1;
int q2;
int q3;
Display display;
x = (display = MIDletProxy.getInstance().getEmulatorScreen()).getGUIElementLeft(this, GUI_ELEMENT_CLIENT);
y = mode == MODE_FULL_SCREEN ?
display.getGUIElementTop(this, GUI_ELEMENT_CLIENT) :
display.getGUIElementTop(this, GUI_ELEMENT_TITLE) +
display.getGUIElementHeight(this, GUI_ELEMENT_TITLE);
render.drawElementOfGUI(6, 5, 0, x - render.getTranslateX(), y - render.getTranslateY(),
display.getWidth() - x, display.getHeight() - y);
q2 = (q3 = width) - (q1 = width / 3);
paintCommand(render, 0, 0, q1, height, commands[0], false, pressedIndex == 0);
paintCommand(render, q2, 0, q3 - q2, height, commands[2], false, pressedIndex == 2);
render.setFont(defaultCommandFont);
paintCommand(render, q1, 0, q2 - q1, height, commands[1], true, pressedIndex == 1);
}
void paintCommand(Graphics render, int left, int top, int width, int height,
Command command, boolean asDefault, boolean asPressed)
{
int ofs;
if(command == null) return;
render.drawElementOfGUI(4, ofs = asPressed ? 1 : asDefault ? 3 : 0, 0, left, top, width, height);
render.setColor(RasterCanvas.getSystemColor(0x24 + ofs));
render.drawString(command.getTruncatedLabel(render.getFont(), width - 4),
left + (width / 2) + (asPressed ? 1 : 0),
top + (asDefault ? -1 : 1) + (asPressed ? 3 : 2),
Graphics.HCENTER | Graphics.TOP);
}
void onShow()
{
}
void onHide()
{
}
void onSizeChanged(int width, int height)
{
sizeChanged(width, height);
}
void onKeyPressed(int key, int charCode)
{
int i = getCommandUnderKey(key);
Command[] c = commandsOnPanel;
if(i < 0 || i >= c.length || c[i] == null) return;
commandPressed = i;
callSeriallyPaintScreen(COMMANDS);
}
void onKeyRepeated(int key, int charCode)
{
}
void onKeyReleased(int key)
{
int i;
Command command;
if((i = commandPressed) < 0) return;
commandPressed = -1;
callSeriallyPaintScreen(COMMANDS);
if(i != getCommandUnderKey(key) || (command = commandsOnPanel[i]) == null) return;
callSeriallyCommandAction(command);
}
void onPointerPressed(int x, int y, int button)
{
int i;
Command[] c;
if(button != MIDletProxy.BUTTON_MAIN) return;
i = getCommandUnderPointer(x, y);
c = commandsOnPanel;
if(i < 0 || i >= c.length || c[i] == null) return;
commandPressed = commandFocused = i;
callSeriallyPaintScreen(COMMANDS);
}
void onPointerDragged(int x, int y)
{
int f;
if((f = commandFocused) < 0 ||
commandPressed == (commandPressed = getCommandUnderPointer(x, y) != f ? -1 : f)) return;
callSeriallyPaintScreen(COMMANDS);
}
void onPointerReleased(int x, int y, int button)
{
int i;
Command command;
if(button != MIDletProxy.BUTTON_MAIN) return;
i = commandPressed;
commandPressed = commandFocused = -1;
if(i < 0) return;
callSeriallyPaintScreen(COMMANDS);
if((command = commandsOnPanel[i]) == null) return;
callSeriallyCommandAction(command);
}
void onPaint(Graphics render, int guiElements, int clipLeft, int clipTop, int clipWidth, int clipHeight)
{
int mode;
int width;
int height;
Ticker ticker;
Display display = MIDletProxy.getInstance().getEmulatorScreen();
if((mode = this.mode) != MODE_FULL_SCREEN)
{
if((guiElements & TITLE) != 0)
{
render.translate(
display.getGUIElementLeft(this, GUI_ELEMENT_TITLE),
display.getGUIElementTop(this, GUI_ELEMENT_TITLE));
width = display.getGUIElementWidth(this, GUI_ELEMENT_TITLE);
height = display.getGUIElementHeight(this, GUI_ELEMENT_TITLE);
render.setFont(getGUIElementFont(GUI_ELEMENT_TITLE));
render.setClip(0, 0, width, height);
paintTitle(render, width, height, getDisplayedTitle(title));
render.reset();
}
if((guiElements & TICKER) != 0 && mode == MODE_WITH_TICKER && (ticker = this.ticker) != null)
{
render.translate(
display.getGUIElementLeft(this, GUI_ELEMENT_TICKER),
display.getGUIElementTop(this, GUI_ELEMENT_TICKER));
width = display.getGUIElementWidth(this, GUI_ELEMENT_TICKER);
height = display.getGUIElementHeight(this, GUI_ELEMENT_TICKER);
render.setFont(getGUIElementFont(GUI_ELEMENT_TICKER));
render.setClip(0, 0, width, height);
paintTicker(render, width, height, ticker);
render.reset();
}
if((guiElements & COMMANDS) != 0)
{
render.translate(
display.getGUIElementLeft(this, GUI_ELEMENT_COMMANDS),
display.getGUIElementTop(this, GUI_ELEMENT_COMMANDS));
width = display.getGUIElementWidth(this, GUI_ELEMENT_COMMANDS);
height = display.getGUIElementHeight(this, GUI_ELEMENT_COMMANDS);
render.setFont(getGUIElementFont(GUI_ELEMENT_COMMANDS));
render.setClip(0, 0, width, height);
paintCommands(render, width, height, commandsOnPanel,
commandPressed, getDefaultCommandFont());
render.reset();
}
}
if((guiElements & CLIENT) != 0)
{
render.translate(
display.getGUIElementLeft(this, GUI_ELEMENT_CLIENT),
display.getGUIElementTop(this, GUI_ELEMENT_CLIENT));
width = display.getGUIElementWidth(this, GUI_ELEMENT_CLIENT);
height = display.getGUIElementHeight(this, GUI_ELEMENT_CLIENT);
render.setFont(getGUIElementFont(GUI_ELEMENT_CLIENT));
render.setClip(0, 0, width, height);
paintClient(render, width, height, clipLeft, clipTop, clipWidth, clipHeight);
}
}
void onCommandAction(Command command)
{
CommandListener listener;
if(command == MENU)
{
menuOpened = true;
callSeriallyPaintScreen();
return;
}
if(command == BACK)
{
menuOpened = false;
callSeriallyPaintScreen();
return;
}
if(command == SELECT)
{
int i;
Command[] c;
menuOpened = false;
callSeriallyPaintScreen();
if((c = commandsOnMenu) == null || (i = menuSelectedIndex) < 0 || i >= c.length ||
(command = c[i]) == null) return;
callSeriallyCommandAction(command);
return;
}
if((listener = this.listener) != null)
{
listener.commandAction(command, this);
}
}
void setDefaultCommand(Command command)
{
boolean changed = false;
synchronized(lock)
{
if(command != this.defaultCommand)
{
this.defaultCommand = command;
changed = true;
}
}
if(changed)
{
updateCommands();
}
}
void setFullScreenMode(boolean fullScreenMode)
{
boolean changedmode;
synchronized(lock)
{
changedmode = mode != (mode = fullScreenMode && listener == null ? MODE_FULL_SCREEN :
ticker != null ? MODE_WITH_TICKER : MODE_WITHOUT_TICKER);
}
if(changedmode)
{
tickerUpdate();
callSeriallySizeChanged();
callSeriallyMenuClose();
}
}
boolean keyHandling(int key)
{
return getCommandUnderKey(key) >= 0;
}
boolean coordinateHandling(int x, int y)
{
return getCommandUnderPointer(x, y) >= 0;
}
int getPanelCommandIndex(int x, int y, int width, int height)
{
int q1;
int q2 = width - (q1 = width / 3);
return x >= q2 && x < width ? 2 : x >= q1 && x < q2 ? 1 : x >= 0 && x < q1 ? 0 : -1;
}
int getClientLeft()
{
return 0;
}
int getClientTop()
{
return 0;
}
int getClientWidth()
{
return MIDletProxy.getInstance().getEmulatorScreen().getGUIElementWidth(this, GUI_ELEMENT_CLIENT);
}
int getClientHeight()
{
return MIDletProxy.getInstance().getEmulatorScreen().getGUIElementHeight(this, GUI_ELEMENT_CLIENT);
}
Font getGUIElementFont(int guiElement)
{
return MIDletProxy.getInstance().getEmulatorScreen().getGUIElementFont(guiElement);
}
Font getDefaultCommandFont()
{
return MIDletProxy.getInstance().getEmulatorScreen().getDefaultCommandFont();
}
CommandEnumeration getCommands()
{
return commandsEnumeration;
}
final void eventShow()
{
if(needSizeChanged)
{
callSeriallySizeChanged();
}
menuOpened = false;
repaintElements = ALL;
commandPressed = commandFocused = -1;
onShow();
}
final void eventHide()
{
menuOpened = false;
onHide();
}
final void eventKeyPressed(int key, int charCode)
{
if(menuOpened)
{
menuKeyPressed(key);
return;
}
onKeyPressed(key, charCode);
}
final void eventKeyRepeated(int key, int charCode)
{
if(menuOpened)
{
menuKeyRepeated(key);
return;
}
onKeyRepeated(key, charCode);
}
final void eventKeyReleased(int key)
{
if(menuOpened)
{
menuKeyReleased(key);
return;
}
onKeyReleased(key);
}
final void eventPointerPressed(int x, int y, int button)
{
if(menuOpened)
{
menuPointerPressed(x, y, button);
return;
}
onPointerPressed(x, y, button);
}
final void eventPointerDragged(int x, int y)
{
if(menuOpened)
{
menuPointerDragged(x, y);
return;
}
onPointerDragged(x, y);
}
final void eventPointerReleased(int x, int y, int button)
{
if(menuOpened)
{
menuPointerReleased(x, y, button);
return;
}
onPointerReleased(x, y, button);
}
final void eventPaint(Graphics render, int guiElements)
{
eventPaint(render, guiElements, 0, 0, getClientWidth(), getClientHeight());
}
final void eventPaint(Graphics render, int guiElements, int clipLeft, int clipTop, int clipWidth, int clipHeight)
{
if(menuOpened)
{
menuPaint(render, guiElements, clipLeft, clipTop, clipWidth, clipHeight);
return;
}
onPaint(render, guiElements, clipLeft, clipTop, clipWidth, clipHeight);
}
final void callSerially(Runnable event)
{
MIDletProxy.getInstance().getEmulatorScreen().callSeriallyEvent(this, event);
}
final void callSeriallySizeChanged()
{
if(!staySizeChanged)
{
staySizeChanged = true;
callSerially(this.new SizeChangedEvent());
}
}
final void callSeriallyPaintScreen()
{
int rge;
repaintElements = (rge = repaintElements) | ALL;
if(rge == 0)
{
MIDletProxy.getInstance().getEmulatorScreen().callSeriallyPaint(this);
}
}
final void callSeriallyPaintScreen(int guiElements)
{
int rge;
repaintElements = (rge = repaintElements) | guiElements;
if(rge == 0)
{
MIDletProxy.getInstance().getEmulatorScreen().callSeriallyPaint(this);
}
}
final void callSeriallyPaintClient(int left, int top, int width, int height)
{
repaintElements |= CLIENT;
MIDletProxy.getInstance().getEmulatorScreen().callSeriallyPaint(this, left, top, width, height);
}
final void callSeriallyCommandAction(Command command)
{
callSerially(this.new CommandActionEvent(command));
}
final void clearRepaintElements()
{
repaintElements = 0;
}
final void updateCommands()
{
if(placeCommandsNeedRepaint())
{
callSeriallyPaintScreen(menuOpened ? CLIENT : COMMANDS);
}
}
final boolean isReallyShown()
{
return MIDletProxy.getInstance().getEmulatorScreen().isShown(this);
}
final int getMode()
{
return mode;
}
final int getRepaintElements()
{
return repaintElements;
}
final Graphics getClientContext()
{
return MIDletProxy.getInstance().getEmulatorScreen().getClientGraphicsFor(this);
}
final Object getCommandsMonitor()
{
return lock;
}
private void menuKeyPressed(int key)
{
int i;
Command[] c;
if(menuMoveCursor(key)) return;
i = getCommandUnderKey(key);
c = MENU_PANEL_COMMANDS;
if(i < 0 || i >= c.length || c[i] == null) return;
commandPressed = i;
callSeriallyPaintScreen(COMMANDS);
}
private void menuKeyRepeated(int key)
{
menuMoveCursor(key);
}
private void menuKeyReleased(int key)
{
int i;
Command command;
if((i = commandPressed) < 0) return;
commandPressed = -1;
callSeriallyPaintScreen(COMMANDS);
if(i != getCommandUnderKey(key) || (command = MENU_PANEL_COMMANDS[i]) == null) return;
callSeriallyCommandAction(command);
}
private void menuPointerPressed(int x, int y, int button)
{
int i;
Command[] c;
if(button != MIDletProxy.BUTTON_MAIN) return;
if((i = getCommandUnderPointer(x, y)) < 0)
{
int l;
int t;
int w;
int h;
int s;
int ofs;
int len;
int width;
int height;
int length;
Display display = MIDletProxy.getInstance().getEmulatorScreen();
s = Math.max(display.getGUIElementFont(GUI_ELEMENT_COMMANDS).getHeight(), 1);
x -= display.getGUIElementLeft(this, GUI_ELEMENT_CLIENT);
y -= display.getGUIElementTop(this, GUI_ELEMENT_CLIENT);
width = display.getGUIElementWidth(this, GUI_ELEMENT_CLIENT);
height = display.getGUIElementHeight(this, GUI_ELEMENT_CLIENT);
synchronized(getCommands().getMonitor())
{
ofs = menuFirstIndex;
len = getMenuCapacity();
length = (c = commandsOnMenu) == null ? 0 : c.length;
l = width - (MENU_OUTER_MARGIN + MENU_INNER_MARGIN + MENU_SPIN_WIDTH);
t = height - (MENU_OUTER_MARGIN + MENU_INNER_MARGIN + 2 * MENU_SPIN_HEIGHT);
w = MENU_SPIN_WIDTH;
h = MENU_SPIN_HEIGHT;
label0:
{
if(ofs > 0 && x >= l && x < l + w && y >= t && y < t + h)
{
menuFirstIndex = ofs - 1;
callSeriallyPaintScreen(CLIENT);
break label0;
}
t += MENU_SPIN_HEIGHT;
if(ofs < length - len && x >= l && x < l + w && y >= t && y < t + h)
{
menuFirstIndex = ofs + 1;
callSeriallyPaintScreen(CLIENT);
break label0;
}
l = MENU_OUTER_MARGIN;
t = height - (h = s * len) - (MENU_OUTER_MARGIN + MENU_INNER_MARGIN);
w = width - (2 * MENU_OUTER_MARGIN + 3 * MENU_INNER_MARGIN + MENU_SPIN_WIDTH);
if(x >= l && x < l + w && y >= t && y < t + h)
{
commandPressed = -2;
if(menuSelectedIndex != (menuSelectedIndex = ofs + (y - t) / s))
{
callSeriallyPaintScreen(CLIENT);
}
}
}
}
return;
}
c = MENU_PANEL_COMMANDS;
if(i >= c.length || c[i] == null) return;
commandPressed = commandFocused = i;
callSeriallyPaintScreen(COMMANDS);
}
private void menuPointerDragged(int x, int y)
{
int f;
int p;
if((p = commandPressed) == -2)
{
int l;
int t;
int w;
int h;
int s;
int ofs;
int len;
int width;
int height;
Display display = MIDletProxy.getInstance().getEmulatorScreen();
s = Math.max(display.getGUIElementFont(GUI_ELEMENT_COMMANDS).getHeight(), 1);
x -= display.getGUIElementLeft(this, GUI_ELEMENT_CLIENT);
y -= display.getGUIElementTop(this, GUI_ELEMENT_CLIENT);
width = display.getGUIElementWidth(this, GUI_ELEMENT_CLIENT);
height = display.getGUIElementHeight(this, GUI_ELEMENT_CLIENT);
synchronized(getCommands().getMonitor())
{
ofs = menuFirstIndex;
len = getMenuCapacity();
l = MENU_OUTER_MARGIN;
t = height - (h = s * len) - (MENU_OUTER_MARGIN + MENU_INNER_MARGIN);
w = width - (2 * MENU_OUTER_MARGIN + 3 * MENU_INNER_MARGIN + MENU_SPIN_WIDTH);
if(x >= l && x < l + w && y >= t && y < t + h &&
menuSelectedIndex != (menuSelectedIndex = ofs + (y - t) / s))
{
callSeriallyPaintScreen(CLIENT);
}
}
return;
}
if((f = commandFocused) < 0 ||
p == (commandPressed = getCommandUnderPointer(x, y) != f ? -1 : f)) return;
callSeriallyPaintScreen(COMMANDS);
}
private void menuPointerReleased(int x, int y, int button)
{
int i;
Command command;
if(button != MIDletProxy.BUTTON_MAIN) return;
if((i = commandPressed) == -1)
{
int l;
int t;
int w;
int h;
int s;
Display display = MIDletProxy.getInstance().getEmulatorScreen();
s = Math.max(display.getGUIElementFont(GUI_ELEMENT_COMMANDS).getHeight(), 1);
l = display.getGUIElementLeft(this, GUI_ELEMENT_CLIENT);
t = display.getGUIElementTop(this, GUI_ELEMENT_CLIENT);
w = display.getGUIElementWidth(this, GUI_ELEMENT_CLIENT);
h = display.getGUIElementHeight(this, GUI_ELEMENT_CLIENT);
synchronized(getCommands().getMonitor())
{
l += MENU_OUTER_MARGIN;
t += h - (h = s * getMenuCapacity() + 2 * MENU_INNER_MARGIN) - MENU_OUTER_MARGIN;
w -= 2 * MENU_OUTER_MARGIN;
}
if((x < l || x >= l + w || y < t || y >= t + h) && (
x < (l = display.getGUIElementLeft(this, GUI_ELEMENT_COMMANDS)) ||
x >= l + display.getGUIElementWidth(this, GUI_ELEMENT_COMMANDS) ||
y < (t = display.getGUIElementTop(this, GUI_ELEMENT_COMMANDS)) ||
y >= (t + display.getGUIElementHeight(this, GUI_ELEMENT_COMMANDS))))
{
menuOpened = false;
callSeriallyPaintScreen();
}
return;
}
commandPressed = commandFocused = -1;
if(i < 0) return;
callSeriallyPaintScreen(COMMANDS);
if((command = MENU_PANEL_COMMANDS[i]) == null) return;
callSeriallyCommandAction(command);
}
private void menuPaint(Graphics render, int guiElements, int clipLeft, int clipTop, int clipWidth, int clipHeight)
{
int mode;
int top;
int left;
int width;
int height;
RasterCanvas canvas = render.getCanvas();
Display display = MIDletProxy.getInstance().getEmulatorScreen();
onPaint(render, guiElements & ~COMMANDS, clipLeft, clipTop, clipWidth, clipHeight);
if((mode = this.mode) != MODE_FULL_SCREEN)
{
if((guiElements & TITLE) != 0)
{
top = display.getGUIElementTop(this, GUI_ELEMENT_TITLE);
left = display.getGUIElementLeft(this, GUI_ELEMENT_TITLE);
width = display.getGUIElementWidth(this, GUI_ELEMENT_TITLE);
height = display.getGUIElementHeight(this, GUI_ELEMENT_TITLE);
canvas.fillRect(left, top, width, height, left, top, width, height, 0x80000000, true);
}
if((guiElements & TICKER) != 0 && mode == MODE_WITH_TICKER && ticker != null)
{
top = display.getGUIElementTop(this, GUI_ELEMENT_TICKER);
left = display.getGUIElementLeft(this, GUI_ELEMENT_TICKER);
width = display.getGUIElementWidth(this, GUI_ELEMENT_TICKER);
height = display.getGUIElementHeight(this, GUI_ELEMENT_TICKER);
canvas.fillRect(left, top, width, height, left, top, width, height, 0x80000000, true);
}
if((guiElements & COMMANDS) != 0)
{
render.reset();
render.translate(
display.getGUIElementLeft(this, GUI_ELEMENT_COMMANDS),
display.getGUIElementTop(this, GUI_ELEMENT_COMMANDS));
width = display.getGUIElementWidth(this, GUI_ELEMENT_COMMANDS);
height = display.getGUIElementHeight(this, GUI_ELEMENT_COMMANDS);
render.setFont(getGUIElementFont(GUI_ELEMENT_COMMANDS));
render.setClip(0, 0, width, height);
paintCommands(render, width, height, MENU_PANEL_COMMANDS,
commandPressed, getDefaultCommandFont());
}
}
if((guiElements & CLIENT) != 0)
{
Graphics clientRender;
top = display.getGUIElementTop(this, GUI_ELEMENT_CLIENT);
left = display.getGUIElementLeft(this, GUI_ELEMENT_CLIENT);
width = display.getGUIElementWidth(this, GUI_ELEMENT_CLIENT);
height = display.getGUIElementHeight(this, GUI_ELEMENT_CLIENT);
canvas.fillRect(left, top, width, height, left, top, width, height, 0x80000000, true);
(clientRender = getClientContext()).reset();
clientRender.setFont(getGUIElementFont(GUI_ELEMENT_COMMANDS));
menuPaint(clientRender, width, height);
}
}
private void menuPaint(Graphics render, int width, int height)
{
int l = MENU_OUTER_MARGIN;
int t = MENU_OUTER_MARGIN;
int w = width - 2 * MENU_OUTER_MARGIN;
int h = height - 2 * MENU_OUTER_MARGIN;
int b;
int s;
int cap;
int sel;
int ofs;
int len;
int lim;
int length;
Command[] c;
Command command;
Font font;
synchronized(getCommands().getMonitor())
{
sel = menuSelectedIndex;
ofs = menuFirstIndex;
cap = (h - 2 * MENU_INNER_MARGIN) / (s = Math.max((font = render.getFont()).getHeight(), 1));
length = (c = commandsOnMenu) == null ? 0 : c.length;
len = Math.min(Math.min(cap, length), MENU_MAX_ELEMENTS);
if(ofs > (b = length - len))
{
menuFirstIndex = ofs = Math.max(b, 0);
}
}
h = s * len + 2 * MENU_INNER_MARGIN;
t = height - h - MENU_OUTER_MARGIN;
render.setColor(RasterCanvas.getSystemColor(0x04));
render.fillRect(l, t, w, h);
l += MENU_INNER_MARGIN;
t += MENU_INNER_MARGIN;
w -= 3 * MENU_INNER_MARGIN + MENU_SPIN_WIDTH;
h -= 2 * MENU_INNER_MARGIN;
render.setColor(RasterCanvas.getSystemColor(0x07));
for(int ti = t + s * len, i = lim = ofs + len; i-- > ofs; )
{
ti -= s;
if(i == sel || (command = c[i]) == null) continue;
render.drawString(command.getTruncatedLabel(font, w - 4), l + 2, ti, Graphics.LEFT | Graphics.TOP);
}
if(sel >= ofs && sel < lim && (command = c[sel]) != null)
{
int ti = t + s * (sel - ofs);
render.setColor(RasterCanvas.getSystemColor(0x0d));
render.fillRect(l, ti, w, s);
render.setColor(RasterCanvas.getSystemColor(0x0e));
render.drawString(command.getTruncatedLabel(font, w - 4), l + 2, ti, Graphics.LEFT | Graphics.TOP);
}
if(ofs > 0 || lim < length)
{
l += w + MENU_INNER_MARGIN;
w = MENU_SPIN_WIDTH;
render.drawElementOfGUI(14, 0, ofs > 0 ? 0 : 2,
l, t + h - 2 * MENU_SPIN_HEIGHT, MENU_SPIN_WIDTH, MENU_SPIN_HEIGHT);
render.drawElementOfGUI(14, 1, lim < length ? 0 : 2,
l, t + h - MENU_SPIN_HEIGHT, MENU_SPIN_WIDTH, MENU_SPIN_HEIGHT);
}
}
private void callSeriallyMenuClose()
{
callSerially(this.new CommandActionEvent(BACK));
}
private boolean placeCommandsNeedRepaint()
{
boolean result;
CommandEnumeration enumeration;
synchronized((enumeration = getCommands()).getMonitor())
{
boolean m;
int i;
int len;
int placed = 1;
Command[] b;
Command[] c = null;
Command left;
Command right;
Command center;
if((center = enumeration.getDefaultCommand()) == null &&
(center = findCommand(enumeration, Command.OK, null)) != null)
{
placed++;
}
right = null;
for(len = COMMAND_TYPES_FOR_SOFT2.length, i = 0; i < len; i++)
{
if((right = findCommand(enumeration, COMMAND_TYPES_FOR_SOFT2[i], center)) == null) continue;
placed++;
break;
}
left = null;
if((len = enumeration.getCommandsCount()) == placed)
{
for(i = len; i-- > 0; )
{
Command command;
if((command = enumeration.getCommand(i)) != null && command != center && command != right)
{
left = command;
break;
}
}
}
else if(len > placed)
{
int j;
for(left = MENU, c = new Command[len - placed + 1], i = j = 0; i < len; i++)
{
Command command;
if((command = enumeration.getCommand(i)) != null && command != center && command != right)
{
c[j++] = command;
}
}
}
len = c == null ? 0 : c.length;
if(!(m = menuOpened))
{
result = (b = commandsOnPanel)[0] != left || b[1] != center || b[2] != right;
}
else if(!(result = ((b = commandsOnMenu) == null ? 0 : b.length) != len))
{
for(i = len; i-- > 0; )
{
if(b[i] != c[i])
{
result = true;
break;
}
}
}
commandsOnMenu = c;
(b = commandsOnPanel)[0] = left;
b[1] = center;
b[2] = right;
if((i = menuSelectedIndex) >= len && i != (menuSelectedIndex = Math.max(0, len - 1)) && m)
{
result = true;
}
}
return result;
}
private boolean menuMoveCursor(int key)
{
MIDletProxy proxy;
if(key == (proxy = MIDletProxy.getInstance()).getKeyUsedAs(MIDletProxy.DEVICE_KEY_UP))
{
synchronized(getCommands().getMonitor())
{
int length;
Command[] c;
if((length = (c = commandsOnMenu) == null ? 0 : c.length) > 0)
{
int first = menuFirstIndex;
int index = menuSelectedIndex = (menuSelectedIndex + length - 1) % length;
if(first > index)
{
menuFirstIndex = index;
}
else if(first <= (index -= getMenuCapacity()))
{
menuFirstIndex = index + 1;
}
callSeriallyPaintScreen(CLIENT);
}
}
return true;
}
if(key == proxy.getKeyUsedAs(MIDletProxy.DEVICE_KEY_DOWN))
{
synchronized(getCommands().getMonitor())
{
int length;
Command[] c;
if((length = (c = commandsOnMenu) == null ? 0 : c.length) > 0)
{
int first = menuFirstIndex;
int index = menuSelectedIndex = (menuSelectedIndex + 1) % length;
if(first > index)
{
menuFirstIndex = index;
}
else if(first <= (index -= getMenuCapacity()))
{
menuFirstIndex = index + 1;
}
callSeriallyPaintScreen(CLIENT);
}
}
return true;
}
return false;
}
private int getMenuCapacity()
{
int h;
int s;
int cap;
int length;
Command[] c;
Display display;
h = (display = MIDletProxy.getInstance().getEmulatorScreen()).getGUIElementHeight(this, GUI_ELEMENT_CLIENT) -
2 * MENU_OUTER_MARGIN;
s = Math.max(display.getGUIElementFont(GUI_ELEMENT_COMMANDS).getHeight(), 1);
cap = (h - 2 * MENU_INNER_MARGIN) / s;
length = (c = commandsOnMenu) == null ? 0 : c.length;
return Math.min(Math.min(cap, length), MENU_MAX_ELEMENTS);
}
private int getCommandUnderKey(int key)
{
int i;
MIDletProxy proxy;
if(mode == MODE_FULL_SCREEN) return -1;
for(proxy = MIDletProxy.getInstance(), i = DEVICE_KEYS_FOR_COMMANDS.length; i-- > 0; )
{
if(key == proxy.getKeyUsedAs(DEVICE_KEYS_FOR_COMMANDS[i])) return i;
}
return -1;
}
private int getCommandUnderPointer(int x, int y)
{
int l;
int t;
int w;
int h;
Display display = MIDletProxy.getInstance().getEmulatorScreen();
return mode == MODE_FULL_SCREEN ||
x < (l = display.getGUIElementLeft(this, GUI_ELEMENT_COMMANDS)) ||
x >= (w = display.getGUIElementWidth(this, GUI_ELEMENT_COMMANDS)) + l ||
y < (t = display.getGUIElementTop(this, GUI_ELEMENT_COMMANDS)) ||
y >= (h = display.getGUIElementHeight(this, GUI_ELEMENT_COMMANDS)) + t ? -1 :
getPanelCommandIndex(x - l, y - t, w, h);
}
private String getDisplayedTitle(String title)
{
Display display = MIDletProxy.getInstance().getEmulatorScreen();
return truncate(title, getGUIElementFont(GUI_ELEMENT_TITLE),
display.getGUIElementWidth(this, GUI_ELEMENT_TITLE) - 4);
}
}