/*
Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
и других спецификаций для функционирования компактных приложений на языке
Java (мидлетов) в среде программного обеспечения Малик Эмулятор.
Copyright © 2016–2017, 2019–2023 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package javax.microedition.lcdui;
import malik.emulator.application.*;
import malik.emulator.microedition.*;
import malik.emulator.microedition.lcdui.*;
public class Form extends ScrollingScreen
{
private static final class Clear extends Object implements Runnable
{
private final int index;
private final Item[] items;
public Clear(Item[] items, int index) {
this.index = index;
this.items = items;
}
public void run() {
Item[] list;
for(int f = index, i = (list = items).length; i-- > 0; )
{
Item current = list[i];
if(i == f) current.onFocusLost();
if(current.visible)
{
current.visible = false;
current.onHide();
}
}
}
}
private static final class Delete extends Object implements Runnable
{
private final boolean hasFocus;
private final Item deleted;
public Delete(Item deleted, boolean hasFocus) {
this.hasFocus = hasFocus;
this.deleted = deleted;
}
public void run() {
Item current = deleted;
if(hasFocus) current.onFocusLost();
if(current.visible)
{
current.visible = false;
current.onHide();
}
}
}
class Helper extends ScrollingScreen.Helper
{
public Helper() {
}
public int size() {
int count = super.size();
Item focused = (Form.this).getFocused();
return count + (focused != null ? focused.getCommands().size() : 0);
}
public Command commandAt(int index) {
int len;
Item focused;
Command.Owner commands;
return
(focused = (Form.this).getFocused()) == null ? super.commandAt(index) :
index < (len = (commands = focused.getCommands()).size()) ? commands.commandAt(index) : super.commandAt(index - len)
;
}
public Command defaultCommand() {
Command result;
Item focused = (Form.this).getFocused();
return focused == null || (result = focused.getCommands().defaultCommand()) == null ? super.defaultCommand() : result;
}
protected void execute() {
servicePlaceItems();
serviceSizeChanged();
servicePlaceItems();
serviceScroll();
servicePaint();
}
protected final void servicePlaceItems() {
(Form.this).placeItems();
}
}
private boolean placeItemsNeeded;
private int focused;
private int count;
private final int[] rect0;
private final int[] rect1;
private final int[] rect2;
private Item[] items;
ItemStateListener listener;
private final Object monitor;
public Form(String title) {
this(title, null, false, null, null);
}
public Form(String title, Item[] items) {
this(title, null, false, null, items);
}
public Form(String title, Ticker ticker, boolean fullScreen, ScrollBarStyle style, Item[] items) {
super(title, ticker, fullScreen, SCROLL_BOTH, style);
int len = items == null ? 0 : items.length;
int error;
int[] monitor;
Item[] list;
this.placeItemsNeeded = true;
this.count = len;
this.rect0 = monitor = new int[4];
this.rect1 = new int[4];
this.rect2 = new int[4];
this.items = list = new Item[getOptimalLength(len)];
this.monitor = monitor;
if(len <= 0) return;
error = 0;
synchronized(Item.OWNER_MONITOR)
{
label0:
{
int i;
label1:
{
for(i = 0; i < len; i++)
{
Item current;
if((current = items[i]) == null)
{
error = 1;
break label1;
}
if(current.owner != null)
{
error = 2;
break label1;
}
(list[i] = current).owner = this;
}
break label0;
}
for(; i-- > 0; list[i].owner = null);
}
}
switch(error)
{
case 1:
throw new NullPointerException("Form: один из элементов аргумента items равен нулевой ссылке.");
case 2:
throw new IllegalStateException("Form: один из элементов аргумента items уже принадлежит экрану или аргумент items содержит равные элементы.");
}
}
public int getWidth() {
return getApplicationWidth();
}
public int getHeight() {
return getApplicationHeight();
}
public void insert(int itemIndex, Item item) {
int error = 0;
synchronized(monitor)
{
label0:
{
int len;
Item[] list;
if(itemIndex < 0 || itemIndex > (len = count))
{
error = 1;
break label0;
}
if(item == null)
{
error = 2;
break label0;
}
synchronized(Item.OWNER_MONITOR)
{
label1:
{
if(item.owner != null)
{
error = 3;
break label1;
}
item.owner = this;
}
}
if(error != 0) break label0;
if(len == (list = items).length) Array.copy(list, 0, list = items = new Item[(len << 1) + 1], 0, len);
if(itemIndex < len) Array.copy(list, itemIndex, list, itemIndex + 1, len - itemIndex);
list[itemIndex] = item;
placeItemsNeeded = true;
count = ++len;
if(len > 1)
{
int activeIndex;
if((activeIndex = focused) >= itemIndex) focused = activeIndex + 1;
}
requestPaint(CLIENT);
}
}
switch(error)
{
case 1:
throw new IndexOutOfBoundsException("Form.insert: аргумент itemIndex выходит из диапазона.");
case 2:
throw new NullPointerException("Form.insert: аргумент item равен нулевой ссылке.");
case 3:
throw new IllegalStateException("Form.insert: аргумент item уже принадлежит экрану.");
}
}
public void delete(int itemIndex) {
int error = 0;
synchronized(monitor)
{
label0:
{
boolean hasFocus;
int len;
Item[] list;
Item deleted;
if(itemIndex < 0 || itemIndex > (len = count - 1))
{
error = 1;
break label0;
}
(deleted = (list = items)[itemIndex]).owner = null;
hasFocus = len <= 0;
if(itemIndex < len) Array.copy(list, itemIndex + 1, list, itemIndex, len - itemIndex);
list[len] = null;
placeItemsNeeded = true;
count = len;
if(len > 0)
{
int activeIndex;
if((activeIndex = focused) == itemIndex)
{
if(activeIndex >= len) activeIndex = len - 1;
focused = activeIndex;
hasFocus = true;
placeCommands();
}
else if(activeIndex > itemIndex)
{
focused = activeIndex - 1;
}
}
requestAction(new Delete(deleted, hasFocus));
requestPaintAll();
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("Form.delete: аргумент itemIndex выходит из диапазона.");
}
}
public void deleteAll() {
synchronized(monitor)
{
int len;
if((len = count) > 0)
{
int indexOfFocused = focused;
Item[] cleared = new Item[len];
Item[] list = items;
placeItemsNeeded = true;
focused = 0;
count = 0;
for(int i = len; i-- > 0; list[i].owner = null);
Array.copy(list, 0, cleared, 0, len);
Array.fill(list, 0, len, null);
placeCommands();
requestAction(new Clear(cleared, indexOfFocused));
requestPaintAll();
}
}
}
public void set(int itemIndex, Item item) {
int error = 0;
synchronized(monitor)
{
label0:
{
boolean hasFocus;
Item[] list;
Item deleted;
if(itemIndex < 0 || itemIndex >= count)
{
error = 1;
break label0;
}
if(item == null)
{
error = 2;
break label0;
}
synchronized(Item.OWNER_MONITOR)
{
label1:
{
if(item.owner != null)
{
error = 3;
break label1;
}
item.owner = this;
}
}
if(error != 0) break label0;
(deleted = (list = items)[itemIndex]).owner = null;
hasFocus = focused == itemIndex;
list[itemIndex] = item;
if(hasFocus) placeCommands();
placeItemsNeeded = true;
requestAction(new Delete(deleted, hasFocus));
requestPaintAll();
}
}
switch(error)
{
case 1:
throw new IndexOutOfBoundsException("Form.set: аргумент itemIndex выходит из диапазона.");
case 2:
throw new NullPointerException("Form.set: аргумент item равен нулевой ссылке.");
case 3:
throw new IllegalStateException("Form.set: аргумент item уже принадлежит экрану.");
}
}
public void setItemStateListener(ItemStateListener listener) {
this.listener = listener;
}
public int size() {
return count;
}
public int append(Item item) {
int result;
int error;
if(item == null)
{
throw new NullPointerException("Form.append: аргумент item равен нулевой ссылке.");
}
error = 0;
synchronized(Item.OWNER_MONITOR)
{
label0:
{
if(item.owner != null)
{
error = 1;
break label0;
}
item.owner = this;
}
}
if(error == 1)
{
throw new IllegalStateException("Form.append: аргумент item уже принадлежит экрану.");
}
synchronized(monitor)
{
Item[] list;
if((result = count) == (list = items).length) Array.copy(list, 0, list = items = new Item[(result << 1) + 1], 0, result);
list[result] = item;
count = result + 1;
placeItemsNeeded = true;
requestPaint(CLIENT);
}
return result;
}
public int append(String text) {
return append(new StringItem(null, text, Item.PLAIN));
}
public int append(Image image) {
return append(new ImageItem(null, image, Item.LAYOUT_DEFAULT, null, Item.PLAIN));
}
public Item get(int itemIndex) {
int error = 0;
Item result;
synchronized(monitor)
{
label0:
{
if(itemIndex < 0 || itemIndex >= count)
{
error = 1;
result = null;
break label0;
}
result = items[itemIndex];
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("Form.get: аргумент itemIndex выходит из диапазона.");
}
return result;
}
void paint(ScreenGraphics render) {
int len;
int clipLeft = render.getRestrictedLeft();
int clipTop = render.getRestrictedTop();
int clipWidth = render.getRestrictedWidth();
int clipHeight = render.getRestrictedHeight();
int translateX = render.getTranslateX() + render.getStartPointX();
int translateY = render.getTranslateY() + render.getStartPointY();
Item[] list;
clipLeft -= translateX;
clipTop -= translateY;
synchronized(monitor)
{
Array.copy(items, 0, list = new Item[len = count], 0, len);
}
for(int i = 0; i < len; i++)
{
Item current;
if((current = list[i]).visible)
{
int left;
int top;
render.reset();
render.translate(translateX, translateY);
render.clipRect(left = current.left, top = current.top, current.width, current.height);
render.clipRect(clipLeft, clipTop, clipWidth, clipHeight);
render.translate(left, top);
current.onPaint(render);
}
}
}
void setFocus(final Item item, Display parent) {
parent.callSerially(new Runnable() {
public void run() {
(Form.this).setFocus(item);
}
});
}
void onShow() {
int viewportWidth = getApplicationWidth();
int viewportHeight = getApplicationHeight();
changeItemVisibility(super.horz.getPosition(), super.vert.getPosition(), viewportWidth, viewportHeight);
moveFocus(Item.DIR_NONE, viewportWidth, viewportHeight, false);
}
void onHide() {
int len;
Item[] list;
Item focused;
if((focused = getFocused()) != null) focused.onFocusLost();
synchronized(monitor)
{
Array.copy(items, 0, list = new Item[len = count], 0, len);
}
for(int i = 0; i < len; i++)
{
Item current;
if((current = list[i]).visible)
{
current.visible = false;
current.onHide();
}
}
}
void onSizeChanged(int width, int height) {
synchronized(monitor)
{
placeItemsNeeded = true;
}
super.onSizeChanged(width, height);
}
void onCommandAction(Command command) {
Item focused;
if((focused = getFocused()) != null && focused.getCommands().isMyOwnedCommand(command))
{
focused.onCommandAction(command);
return;
}
super.onCommandAction(command);
}
void onClientKeyboardEvent(KeyboardEvent event) {
boolean moved = false;
int key = event.getKey();
int action = event.getAction();
int viewportWidth = getApplicationWidth();
int viewportHeight = getApplicationHeight();
DeviceSettings settings = DeviceManager.getInstance().getSettings();
Item activeItem = null;
if(key == settings.getKeyUsedAs(DeviceSettings.DEVICE_KEY_LEFT))
{
if((action == KeyboardEvent.ACTION_KEY_PRESSED || action == KeyboardEvent.ACTION_KEY_REPEATED) && !moveFocus(Item.DIR_LEFT, viewportWidth, viewportHeight, false))
{
synchronized(monitor)
{
int activeIndex;
Item[] list = items;
if((activeIndex = focused) > 0)
{
moved = true;
activeItem = list[activeIndex];
focused = activeIndex - 1;
placeCommands();
requestPaintAll();
}
}
if(moved)
{
activeItem.onFocusLost();
moveFocus(Item.DIR_LEFT, viewportWidth, viewportHeight, true);
} else
{
super.horz.scroll(-16);
}
}
return;
}
if(key == settings.getKeyUsedAs(DeviceSettings.DEVICE_KEY_RIGHT))
{
if((action == KeyboardEvent.ACTION_KEY_PRESSED || action == KeyboardEvent.ACTION_KEY_REPEATED) && !moveFocus(Item.DIR_RIGHT, viewportWidth, viewportHeight, false))
{
synchronized(monitor)
{
int activeIndex;
Item[] list = items;
if((activeIndex = focused) < count - 1)
{
moved = true;
activeItem = list[activeIndex];
focused = activeIndex + 1;
placeCommands();
requestPaintAll();
}
}
if(moved)
{
activeItem.onFocusLost();
moveFocus(Item.DIR_RIGHT, viewportWidth, viewportHeight, true);
} else
{
super.horz.scroll(+16);
}
}
return;
}
if(key == settings.getKeyUsedAs(DeviceSettings.DEVICE_KEY_UP))
{
if((action == KeyboardEvent.ACTION_KEY_PRESSED || action == KeyboardEvent.ACTION_KEY_REPEATED) && !moveFocus(Item.DIR_UP, viewportWidth, viewportHeight, false))
{
synchronized(monitor)
{
int activeIndex;
if((activeIndex = focused) > 0)
{
int lnCount = 0;
Item[] list;
activeItem = (list = items)[activeIndex];
for(; activeIndex >= 0; activeIndex--)
{
Item current;
if((current = list[activeIndex]).newLine) lnCount++;
if(lnCount == 2)
{
if(current.visible)
{
moved = true;
focused = activeIndex;
placeCommands();
requestPaintAll();
}
break;
}
}
}
}
if(moved)
{
activeItem.onFocusLost();
moveFocus(Item.DIR_UP, viewportWidth, viewportHeight, true);
} else
{
super.vert.scroll(-Item.LABEL_FONT.getHeight());
}
}
return;
}
if(key == settings.getKeyUsedAs(DeviceSettings.DEVICE_KEY_DOWN))
{
if((action == KeyboardEvent.ACTION_KEY_PRESSED || action == KeyboardEvent.ACTION_KEY_REPEATED) && !moveFocus(Item.DIR_DOWN, viewportWidth, viewportHeight, false))
{
synchronized(monitor)
{
int len;
int activeIndex;
if((activeIndex = focused) < (len = count) - 1)
{
Item[] list;
activeItem = (list = items)[activeIndex++];
for(; activeIndex < len; activeIndex++)
{
Item current;
if((current = list[activeIndex]).newLine)
{
if(current.visible)
{
moved = true;
focused = activeIndex;
placeCommands();
requestPaintAll();
}
break;
}
}
}
}
if(moved)
{
activeItem.onFocusLost();
moveFocus(Item.DIR_DOWN, viewportWidth, viewportHeight, true);
} else
{
super.vert.scroll(+Item.LABEL_FONT.getHeight());
}
}
return;
}
if((activeItem = getFocused()) != null) activeItem.onKeyboardEvent(event);
}
void onClientPointerEvent(PointerEvent event) {
Item activeItem = null;
Item focusedItem = null;
if(event.getAction() == PointerEvent.ACTION_POINTER_PRESSED)
{
int x = event.getX();
int y = event.getY();
synchronized(monitor)
{
Item[] list;
activeItem = (list = items)[focused];
for(int i = count; i-- > 0; )
{
int left;
int top;
Item current = list[i];
if(x >= (left = current.left) && x < left + current.width && y >= (top = current.top) && y < top + current.height)
{
focusedItem = current;
focused = i;
placeCommands();
requestPaintAll();
break;
}
}
}
}
if(activeItem != null && focusedItem != null && activeItem != focusedItem)
{
activeItem.onFocusLost();
moveFocus(Item.DIR_NONE, getApplicationWidth(), getApplicationHeight(), true);
}
if((activeItem = getFocused()) != null)
{
int[] rect = rect0;
activeItem.writeContentRectangleTo(rect);
event.translate(activeItem.left + rect[0], activeItem.top + rect[1]);
activeItem.onPointerEvent(event);
}
}
void onClientScroll(int positionHorizontal, int positionVertical, int clientWidth, int clientHeight) {
changeItemVisibility(positionHorizontal, positionVertical, clientWidth, clientHeight);
}
boolean focusSupported() {
return true;
}
boolean isFocused(Item item) {
return item != null && item == items[focused];
}
Displayable.Helper createHelper() {
return this.new Helper();
}
final void requestStateChanged(final Item item) {
requestAction(item == null ? null : new Runnable() {
public void run() {
ItemStateListener listener;
if((listener = (Form.this).listener) != null) listener.itemStateChanged(item);
}
});
}
final void requestInvalidate() {
synchronized(monitor)
{
placeItemsNeeded = true;
}
requestPaint(CLIENT);
}
final strictfp void placeItems() {
boolean needed;
int len;
int clientWidth;
int clientHeight;
int scrollWidth;
int scrollHeight;
int[] layouts;
int[] prefWidths;
int[] prefHeights;
Item[] list;
Item current;
ScrollBar horz;
ScrollBar vert;
synchronized(monitor)
{
if(needed = placeItemsNeeded) placeItemsNeeded = false;
}
if(!needed) return;
clientWidth = getApplicationWidth();
clientHeight = getApplicationHeight();
scrollWidth = clientWidth;
scrollHeight = 0;
synchronized(monitor)
{
Array.copy(items, 0, list = new Item[len = count], 0, len);
}
layouts = new int[len];
prefWidths = new int[len];
prefHeights = new int[len];
for(int i = 0; i < len; i++)
{
int layout;
int minWidth;
int prefWidth;
(current = list[i]).resetContentSize();
layouts[i] = (layout = current.suppliedLayout()) == Item.LAYOUT_DEFAULT ? (layout = current.getDefaultLayout()) : layout;
prefWidths[i] = prefWidth = current.suppliedPreferredWidth();
prefHeights[i] = current.suppliedPreferredHeight();
current.newLine = false;
current.minimumWidth = minWidth = current.computeMinimumWidth();
current.minimumHeight = current.computeMinimumHeight();
if((layout & Item.LAYOUT_SHRINK) != 0)
{
current.width = minWidth;
} else
{
if(minWidth >= prefWidth)
{
prefWidth = current.computePreferredWidth(-1);
if(minWidth > prefWidth) prefWidth = minWidth;
}
current.width = prefWidth;
}
}
for(int rowHeight, rowEnd, rowBegin = 0; rowBegin < len; scrollHeight += rowHeight, rowBegin = rowEnd)
{
/* определение содержимого строки */
int left;
int rowWidth;
int alignment;
int currentAlignment;
int layout = layouts[rowEnd = rowBegin];
(current = list[rowEnd++]).newLine = true;
currentAlignment = (alignment = layout & Item.LAYOUT_CENTER) != 0 ? alignment : Item.LAYOUT_LEFT;
if((rowWidth = current.width) < clientWidth) for(int newWidth; !current.hasRowBreakAfter(layout, currentAlignment) && rowEnd < len; rowWidth = newWidth, rowEnd++)
{
layout = layouts[rowEnd];
current = list[rowEnd];
newWidth = rowWidth + current.width;
if(current.hasRowBreakBefore(layout, currentAlignment) || newWidth < 0 || newWidth > clientWidth) break;
}
/* расширение усаживаемых по ширине элементов */
if(rowWidth < clientWidth)
{
double difference = 0.d;
for(int i = rowBegin; i < rowEnd; i++)
{
if((layouts[i] & Item.LAYOUT_SHRINK) != 0)
{
int minWidth = (current = list[i]).minimumWidth;
int prefWidth = prefWidths[i];
if(minWidth >= prefWidth)
{
prefWidth = current.computePreferredWidth(-1);
if(minWidth > prefWidth) prefWidth = minWidth;
}
prefWidths[i] = prefWidth;
difference += (double) (prefWidth - minWidth);
}
}
if(difference > 0.d)
{
double koefficient;
if((koefficient = (double) (clientWidth - rowWidth) / difference) > 1.d) koefficient = 1.d;
for(int i = rowBegin; i < rowEnd; i++) if((layouts[i] & Item.LAYOUT_SHRINK) != 0)
{
int delta = (int) (koefficient * (double) (prefWidths[i] - (current = list[i]).minimumWidth));
current.width += delta;
rowWidth += delta;
}
}
}
/* расширение растягиваемых по ширине элементов */
if(rowWidth < clientWidth)
{
int count = 0;
for(int i = rowBegin; i < rowEnd; i++) if((layouts[i] & Item.LAYOUT_EXPAND) != 0) count++;
if(count > 0)
{
int delta = (clientWidth - rowWidth) / count;
for(int i = rowBegin; i < rowEnd; i++) if((layouts[i] & Item.LAYOUT_EXPAND) != 0)
{
current = list[i];
if(count <= 1)
{
delta = clientWidth - rowWidth;
current.width += delta;
rowWidth += delta;
break;
}
current.width += delta;
rowWidth += delta;
count--;
}
}
}
/* определение высоты строки */
rowHeight = 0;
for(int i = rowBegin; i < rowEnd; i++)
{
int height;
current = list[i];
if((layouts[i] & Item.LAYOUT_VSHRINK) != 0)
{
current.height = height = current.minimumHeight;
} else
{
int minHeight = current.minimumHeight;
int prefHeight = prefHeights[i];
if(minHeight >= prefHeight)
{
prefHeight = current.computePreferredHeight(current.width);
if(minHeight > prefHeight) prefHeight = minHeight;
}
current.height = height = prefHeight;
}
if(rowHeight < height) rowHeight = height;
}
/* расширение растягиваемых по высоте элементов */
for(int i = rowBegin; i < rowEnd; i++)
{
current = list[i];
if(((layout = layouts[i]) & Item.LAYOUT_VEXPAND) != 0)
{
int minWidth;
int maxWidth;
int prefWidth;
current.height = rowHeight;
if((layout & (Item.LAYOUT_SHRINK | Item.LAYOUT_EXPAND)) == 0 && (prefWidth = prefWidths[i]) <= (minWidth = current.minimumWidth))
{
int delta;
prefWidth = current.computePreferredWidth(rowHeight);
if(minWidth > prefWidth) prefWidth = minWidth;
if((maxWidth = current.width) < prefWidth) prefWidth = maxWidth;
delta = prefWidth - maxWidth;
current.width += delta;
rowWidth += delta;
}
}
current.onSizeChanged();
}
/* размещение элементов строки */
switch(currentAlignment)
{
default:
left = 0;
break;
case Item.LAYOUT_CENTER:
left = (clientWidth - rowWidth) >> 1;
break;
case Item.LAYOUT_RIGHT:
left = clientWidth - rowWidth;
break;
}
if(left < 0) left = 0;
for(int i = rowBegin; i < rowEnd; left += current.width, i++)
{
(current = list[i]).left = left;
switch((layouts[i] & Item.LAYOUT_VCENTER) >> 4)
{
case Item.LAYOUT_TOP >> 4:
current.top = scrollHeight;
break;
case Item.LAYOUT_VCENTER >> 4:
current.top = scrollHeight + ((rowHeight - current.height) >> 1);
break;
default:
current.top = scrollHeight + (rowHeight - current.height);
break;
}
}
if(scrollWidth < rowWidth) scrollWidth = rowWidth;
}
/* обновление диапазонов прокрутки */
(horz = super.horz).setRange(scrollWidth);
(vert = super.vert).setRange(scrollHeight);
/* прокрутка формы */
moveFocus(Item.DIR_NONE, clientWidth, clientHeight, false);
/* определение видимости элементов */
changeItemVisibility(horz.getPosition(), vert.getPosition(), clientWidth, clientHeight);
}
final void setFocus(Item item) {
Item activeItem = null;
Item focusedItem = null;
synchronized(monitor)
{
int index;
Item[] list;
activeItem = (list = items)[focused];
if((index = Array.findf(list, 0, item)) < count)
{
focusedItem = item;
focused = index;
placeCommands();
requestPaintAll();
}
}
if(activeItem != null && focusedItem != null && activeItem != focusedItem)
{
placeItems();
activeItem.onFocusLost();
moveFocus(Item.DIR_NONE, getApplicationWidth(), getApplicationHeight(), true);
}
}
final Item getFocused() {
return items[focused];
}
private void changeItemVisibility(int left, int top, int width, int height) {
int len;
Item[] list;
synchronized(monitor)
{
Array.copy(items, 0, list = new Item[len = count], 0, len);
}
for(int i = 0; i < len; i++)
{
boolean visibility;
int l;
int t;
int w;
int h;
Item current = list[i];
l = current.left;
t = current.top;
w = current.width;
h = current.height;
visibility = left < l + w && top < t + h && left + width > l && top + height > t;
if(current.visible && !visibility)
{
current.visible = false;
current.onHide();
}
else if(!current.visible && visibility)
{
current.visible = true;
current.onShow();
}
}
}
private boolean moveFocus(int direction, int viewportWidth, int viewportHeight, boolean initialFocus) {
Item focused;
if((focused = getFocused()) != null)
{
int viewportLeft = super.horz.getPosition();
int viewportTop = super.vert.getPosition();
int contentLeft;
int contentTop;
int focusedLeft = focused.left;
int focusedTop = focused.top;
int[] viewportRect = rect0;
int[] contentRect = rect1;
int[] visibleRect = rect2;
if(initialFocus)
{
int focusedWidth = focused.width;
int focusedHeight = focused.height;
int focusedRight = focusedLeft + focusedWidth;
int focusedBottom = focusedTop + focusedHeight;
if(focusedWidth > viewportWidth)
{
if(viewportLeft + viewportWidth > focusedRight && (viewportLeft = focusedRight - viewportWidth) < 0) viewportLeft = 0;
if(viewportLeft < focusedLeft) viewportLeft = focusedLeft;
} else
{
if(viewportLeft + viewportWidth < focusedRight) viewportLeft = focusedRight - viewportWidth;
if(viewportLeft > focusedLeft) viewportLeft = focusedLeft;
}
if(focusedHeight > viewportHeight)
{
if(viewportTop + viewportHeight > focusedBottom && (viewportTop = focusedBottom - viewportHeight) < 0) viewportTop = 0;
if(viewportTop < focusedTop) viewportTop = focusedTop;
} else
{
if(viewportTop + viewportHeight < focusedBottom) viewportTop = focusedBottom - viewportHeight;
if(viewportTop > focusedTop) viewportTop = focusedTop;
}
}
focused.writeContentRectangleTo(contentRect);
contentLeft = focusedLeft + contentRect[0];
contentTop = focusedTop + contentRect[1];
viewportRect[0] = viewportLeft;
viewportRect[1] = viewportTop;
viewportRect[2] = viewportLeft + viewportWidth;
viewportRect[3] = viewportTop + viewportHeight;
contentRect[2] += focusedLeft;
contentRect[3] += focusedTop;
visibleRect[0] = Math.max(viewportRect[0], contentLeft);
visibleRect[1] = Math.max(viewportRect[1], contentTop);
visibleRect[2] = Math.min(viewportRect[2], contentRect[2]);
visibleRect[3] = Math.min(viewportRect[3], contentRect[3]);
if((visibleRect[2] -= visibleRect[0]) < 0) visibleRect[2] = 0;
if((visibleRect[3] -= visibleRect[1]) < 0) visibleRect[3] = 0;
visibleRect[0] -= contentLeft;
visibleRect[1] -= contentTop;
if(focused.onFocusMove(direction, viewportWidth, viewportHeight, visibleRect))
{
int left = contentLeft + visibleRect[0];
int top = contentTop + visibleRect[1];
int right = left + visibleRect[2];
int bottom = top + visibleRect[3];
if(viewportLeft + viewportWidth < right) viewportLeft = right - viewportWidth;
if(viewportTop + viewportHeight < bottom) viewportTop = bottom - viewportHeight;
if(viewportLeft > left) viewportLeft = left;
if(viewportTop > top) viewportTop = top;
super.scrollTo(viewportLeft, viewportTop);
return true;
}
if(initialFocus) super.scrollTo(viewportLeft, viewportTop);
}
return false;
}
}