/*
Реализация спецификаций 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.media.graphics.*;
import malik.emulator.microedition.*;
import malik.emulator.microedition.lcdui.*;
public class ChoiceGroup extends InteractiveItem implements Choice
{
static final int ICON_WIDTH = 24;
static final int ICON_HEIGHT = 24;
private static final int MARGIN = 3;
private static final int POPUP_ARROW_SIZE = 9;
private static final String DEFAULT_EMPTY_LABEL = "(пусто)";
private static final int MARGIN1;
private static final int MARGIN2;
private static final int MARGIN3;
private static final int ICON_TOP;
private static final int CHECKBOX_TOP;
private static final int CHECKBOX_WIDTH;
private static final int CHECKBOX_HEIGHT;
private static final int ELEMENT_HEIGHT;
private static final Command[] MULTIPLE_ACTIONS;
private static final Command CHECK_COMMAND;
private static final Command SELECT_COMMAND;
static {
int i;
int s = RasterCanvas.getGUIElementSize(15, 0, 0);
int w = (i = (short) s) <= 0 ? 16 : i > ICON_WIDTH ? ICON_WIDTH : i;
int h = (i = s >> 16) <= 0 ? 16 : i > ICON_HEIGHT ? ICON_HEIGHT : i;
int height1 = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_MEDIUM).getHeight();
int height2 = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL).getHeight();
int height3 = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_LARGE).getHeight();
int heightMax = Math.max(Math.max(height1, height2), Math.max(height3, ICON_HEIGHT)) + 2 * MARGIN;
MARGIN1 = MARGIN * 2 + w;
MARGIN2 = MARGIN + ICON_WIDTH + MARGIN1;
MARGIN3 = MARGIN + ICON_WIDTH + MARGIN;
ICON_TOP = (heightMax - ICON_HEIGHT) >> 1;
CHECKBOX_TOP = (heightMax - h) >> 1;
CHECKBOX_WIDTH = w;
CHECKBOX_HEIGHT = h;
ELEMENT_HEIGHT = heightMax;
MULTIPLE_ACTIONS = new Command[] {
new Command("Отметить все", Command.ITEM, Integer.MAX_VALUE),
new Command("Снять все", Command.ITEM, Integer.MAX_VALUE),
new Command("Переключить все", Command.ITEM, Integer.MAX_VALUE)
};
CHECK_COMMAND = new Command("\u2713", Command.OK, 0);
SELECT_COMMAND = new Command("Выбрать", Command.OK, 0);
}
private final byte type;
private int listWidth;
private int listHeight;
private int fitPolicy;
private int selected;
private int checked;
private int focused;
private int pressed;
private int count;
private ChoiceElement[] elements;
private final ChoiceList popupMenu;
private final String emptyLabel;
private final ChoiceElementViewer monitor;
public ChoiceGroup(String label, int type) {
this(label, type, null, new String[0], null);
}
public ChoiceGroup(String label, int type, String[] elements, Image[] icons) {
this(label, type, null, elements, icons);
}
public ChoiceGroup(String label, int type, String emptyLabel, String[] elements, Image[] icons) {
super(label);
int count;
String[] copyElements;
ChoiceElement[] choiceElements;
if(type != POPUP && type != EXCLUSIVE && type != MULTIPLE)
{
throw new IllegalArgumentException("ChoiceGroup: аргумент type имеет недопустимое значение.");
}
if(elements == null)
{
throw new NullPointerException("ChoiceGroup: аргумент elements равен нулевой ссылке.");
}
Array.copy(elements, 0, copyElements = new String[count = elements.length], 0, count);
if(Array.findf(copyElements, 0, null) < count)
{
throw new NullPointerException("ChoiceGroup: аргумент elements содержит элементы, равные нулевой ссылке.");
}
if(icons != null && icons.length != count)
{
throw new IllegalArgumentException("ChoiceGroup: длина аргумента icons отличается от длины аргумента elements.");
}
choiceElements = new ChoiceElement[Displayable.getOptimalLength(count)];
for(int i = count; i-- > 0; ) choiceElements[i] = new ChoiceElement(type == EXCLUSIVE && i == 0, copyElements[i], icons != null ? icons[i] : null);
for(int len = type == MULTIPLE ? MULTIPLE_ACTIONS.length : 0, i = 0; i < len; i++) super.addCommand(MULTIPLE_ACTIONS[i]);
if(count > 0) super.setDefaultCommand(type == POPUP ? SELECT_COMMAND : CHECK_COMMAND);
this.type = (byte) type;
this.fitPolicy = TEXT_WRAP_DEFAULT;
this.focused = -1;
this.pressed = -1;
this.count = count;
this.elements = choiceElements;
this.popupMenu = type == POPUP ? createPopupMenu() : null;
this.emptyLabel = emptyLabel == null ? DEFAULT_EMPTY_LABEL : emptyLabel;
this.monitor = new ChoiceElementViewer();
}
public void insert(int elementIndex, String text, Image icon) {
int error;
if(text == null)
{
throw new NullPointerException("ChoiceGroup.insert: аргумент text равен нулевой ссылке.");
}
error = 0;
synchronized(monitor)
{
label0:
{
int t;
int len;
ChoiceElement[] list;
ChoiceList menu;
if(elementIndex < 0 || elementIndex > (len = count))
{
error = 1;
break label0;
}
list = elements;
if(len == list.length) Array.copy(list, 0, list = elements = new ChoiceElement[(len << 1) + 1], 0, len);
if(elementIndex < len) Array.copy(list, elementIndex, list, elementIndex + 1, len - elementIndex);
list[elementIndex] = new ChoiceElement((t = type) == EXCLUSIVE && len == 0, text, icon);
focused = -1;
pressed = -1;
count = ++len;
if(len > 1)
{
int activeIndex;
if(t == EXCLUSIVE && (activeIndex = checked) >= elementIndex) checked = activeIndex + 1;
if((activeIndex = selected) >= elementIndex) selected = activeIndex + 1;
} else
{
super.setDefaultCommand(t == POPUP ? SELECT_COMMAND : CHECK_COMMAND);
}
if(t != POPUP)
{
requestInvalidate();
}
else if((menu = popupMenu).isShown())
{
menu.insert(elementIndex, text, icon);
}
else if(len <= 1)
{
requestPaint();
}
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("ChoiceGroup.insert: аргумент elementIndex выходит из диапазона.");
}
}
public void delete(int elementIndex) {
int error = 0;
synchronized(monitor)
{
label0:
{
boolean needRepaint;
int t;
int len;
ChoiceElement[] list;
ChoiceList menu;
if(elementIndex < 0 || elementIndex > (len = count - 1))
{
error = 1;
break label0;
}
list = elements;
if(elementIndex < len) Array.copy(list, elementIndex + 1, list, elementIndex, len - elementIndex);
list[len] = null;
focused = -1;
pressed = -1;
count = len;
if(len > 0)
{
int activeIndex;
needRepaint = false;
if((t = type) == EXCLUSIVE)
{
if((activeIndex = checked) == elementIndex)
{
if(activeIndex >= len) activeIndex = len - 1;
list[activeIndex].selected = true;
checked = activeIndex;
}
else if(activeIndex > elementIndex)
{
checked = activeIndex - 1;
}
}
if((activeIndex = selected) == elementIndex)
{
if(activeIndex >= len) activeIndex = len - 1;
needRepaint = true;
selected = activeIndex;
}
else if(activeIndex > elementIndex)
{
selected = activeIndex - 1;
}
} else
{
needRepaint = true;
super.removeCommand((t = type) == POPUP ? SELECT_COMMAND : CHECK_COMMAND);
}
if(t != POPUP)
{
requestInvalidate();
}
else if((menu = popupMenu).isShown())
{
menu.delete(elementIndex);
}
else if(needRepaint)
{
requestPaint();
}
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("ChoiceGroup.delete: аргумент elementIndex выходит из диапазона.");
}
}
public void deleteAll() {
synchronized(monitor)
{
int len;
if((len = count) > 0)
{
int t;
ChoiceList menu;
selected = 0;
checked = 0;
focused = -1;
pressed = -1;
count = 0;
Array.fill(elements, 0, len, null);
super.removeCommand((t = type) == POPUP ? SELECT_COMMAND : CHECK_COMMAND);
if(t != POPUP)
{
requestInvalidate();
}
else if((menu = popupMenu).isShown())
{
menu.deleteAll();
}
else
{
requestPaint();
}
}
}
}
public void setFitPolicy(int fitPolicy) {
if(fitPolicy != TEXT_WRAP_DEFAULT && fitPolicy != TEXT_WRAP_ON && fitPolicy != TEXT_WRAP_OFF)
{
throw new IllegalArgumentException("ChoiceGroup.setFitPolicy: аргумент fitPolicy имеет недопустимое значение.");
}
this.fitPolicy = fitPolicy;
}
public void setSelectedIndex(int elementIndex, boolean selected) {
int error = 0;
synchronized(monitor)
{
label0:
{
int activeIndex;
ChoiceElement item;
ChoiceElement[] list;
if(elementIndex < 0 || elementIndex >= count)
{
error = 1;
break label0;
}
list = elements;
switch(type)
{
case EXCLUSIVE:
if(selected && (activeIndex = checked) != elementIndex)
{
list[activeIndex].selected = false;
list[elementIndex].selected = true;
checked = elementIndex;
requestPaint();
}
break;
case MULTIPLE:
if((item = list[elementIndex]).selected != selected)
{
item.selected = selected;
requestPaint();
}
break;
default:
if(selected && this.selected != elementIndex)
{
ChoiceList menu;
this.selected = elementIndex;
if((menu = popupMenu).isShown())
{
menu.setSelectedIndex(elementIndex);
} else
{
requestPaint();
}
}
break;
}
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("ChoiceGroup.setSelectedIndex: аргумент elementIndex выходит из диапазона.");
}
}
public void setSelectedFlags(boolean[] src) {
int error;
if(src == null)
{
throw new NullPointerException("ChoiceGroup.setSelectedFlags: аргумент src равен нулевой ссылке.");
}
error = 0;
synchronized(monitor)
{
label0:
{
boolean needRepaint;
int len;
int activeIndex;
int elementIndex;
ChoiceElement[] list;
if(src.length < (len = count))
{
error = 1;
break label0;
}
list = elements;
switch(type)
{
case EXCLUSIVE:
if((elementIndex = Array.findf(src, 0, true)) < len && (activeIndex = checked) != elementIndex)
{
list[activeIndex].selected = false;
list[elementIndex].selected = true;
checked = elementIndex;
requestPaint();
}
break;
case MULTIPLE:
needRepaint = false;
for(int i = len; i-- > 0; )
{
boolean selected;
ChoiceElement item;
if((item = list[i]).selected != (selected = src[i]))
{
needRepaint = true;
item.selected = selected;
}
}
if(needRepaint) requestPaint();
break;
default:
if((elementIndex = Array.findf(src, 0, true)) < len && selected != elementIndex)
{
ChoiceList menu;
selected = elementIndex;
if((menu = popupMenu).isShown())
{
menu.setSelectedIndex(elementIndex);
} else
{
requestPaint();
}
}
break;
}
}
}
if(error == 1)
{
throw new IllegalArgumentException("ChoiceGroup.setSelectedFlags: аргумент src короче списка.");
}
}
public void setFont(int elementIndex, Font font) {
int error = 0;
if(font == null) font = Font.getDefaultFont();
synchronized(monitor)
{
label0:
{
ChoiceList menu;
if(elementIndex < 0 || elementIndex >= count)
{
error = 1;
break label0;
}
elements[elementIndex].font = font;
if((menu = popupMenu) != null && menu.isShown())
{
menu.setFont(elementIndex, font);
}
else if(type != POPUP || selected == elementIndex)
{
requestPaint();
}
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("ChoiceGroup.setFont: аргумент elementIndex выходит из диапазона.");
}
}
public void set(int elementIndex, String text, Image icon) {
int error;
if(text == null)
{
throw new NullPointerException("ChoiceGroup.set: аргумент text равен нулевой ссылке.");
}
error = 0;
synchronized(monitor)
{
label0:
{
ChoiceList menu;
ChoiceElement item;
if(elementIndex < 0 || elementIndex >= count)
{
error = 1;
break label0;
}
(item = elements[elementIndex]).text = text;
item.icon = icon;
if((menu = popupMenu) != null && menu.isShown())
{
menu.setString(elementIndex, text, icon);
}
else if(type != POPUP || selected == elementIndex)
{
requestPaint();
}
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("ChoiceGroup.set: аргумент elementIndex выходит из диапазона.");
}
}
public boolean isSelected(int elementIndex) {
boolean result;
int error = 0;
synchronized(monitor)
{
label0:
{
if(elementIndex < 0 || elementIndex >= count)
{
error = 1;
result = false;
break label0;
}
result = type != POPUP ? elements[elementIndex].selected : elementIndex == selected;
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("ChoiceGroup.isSelected: аргумент elementIndex выходит из диапазона.");
}
return result;
}
public int append(String text, Image icon) {
int result;
if(text == null)
{
throw new NullPointerException("ChoiceGroup.append: аргумент text равен нулевой ссылке.");
}
synchronized(monitor)
{
int t;
int len;
ChoiceElement[] list;
ChoiceList menu;
if((result = len = count) == (list = elements).length) Array.copy(list, 0, list = elements = new ChoiceElement[(len << 1) + 1], 0, len);
list[len] = new ChoiceElement((t = type) == EXCLUSIVE && len == 0, text, icon);
focused = -1;
pressed = -1;
count = ++len;
if(len <= 1) super.setDefaultCommand(t == POPUP ? SELECT_COMMAND : CHECK_COMMAND);
if(t != POPUP)
{
requestInvalidate();
}
else if((menu = popupMenu).isShown())
{
menu.append(text, icon);
}
else if(len <= 1)
{
requestPaint();
}
}
return result;
}
public int size() {
return count;
}
public int getFitPolicy() {
return fitPolicy;
}
public int getSelectedIndex() {
switch(type)
{
case EXCLUSIVE:
return count > 0 ? checked : -1;
case MULTIPLE:
return -1;
default:
return count > 0 ? selected : -1;
}
}
public int getSelectedFlags(boolean[] dst) {
int result;
int error;
if(dst == null)
{
throw new NullPointerException("ChoiceGroup.getSelectedFlags: аргумент dst равен нулевой ссылке.");
}
error = 0;
synchronized(monitor)
{
label0:
{
int len;
int dstlen;
ChoiceElement[] list;
if((dstlen = dst.length) < (len = count))
{
error = 1;
result = 0;
break label0;
}
Array.fill(dst, 0, dstlen, false);
list = elements;
if(type != POPUP)
{
result = 0;
for(int i = len; i-- > 0; ) if(dst[i] = list[i].selected) result++;
} else
{
result = 1;
dst[selected] = true;
}
}
}
if(error == 1)
{
throw new IllegalArgumentException("ChoiceGroup.getSelectedFlags: аргумент dst короче списка.");
}
return result;
}
public Font getFont(int elementIndex) {
int error = 0;
Font result;
synchronized(monitor)
{
label0:
{
if(elementIndex < 0 || elementIndex >= count)
{
error = 1;
result = null;
break label0;
}
result = elements[elementIndex].font;
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("ChoiceGroup.getFont: аргумент elementIndex выходит из диапазона.");
}
return result;
}
public Image getImage(int elementIndex) {
int error = 0;
Image result;
synchronized(monitor)
{
label0:
{
if(elementIndex < 0 || elementIndex >= count)
{
error = 1;
result = null;
break label0;
}
result = elements[elementIndex].icon;
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("ChoiceGroup.getImage: аргумент elementIndex выходит из диапазона.");
}
return result;
}
public String getString(int elementIndex) {
int error = 0;
String result;
synchronized(monitor)
{
label0:
{
if(elementIndex < 0 || elementIndex >= count)
{
error = 1;
result = null;
break label0;
}
result = elements[elementIndex].text;
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("ChoiceGroup.getString: аргумент elementIndex выходит из диапазона.");
}
return result;
}
void paint(Graphics render, int contentWidth, int contentHeight) {
int type = this.type;
int top1 = render.getClipY();
int top2 = render.getClipHeight() + top1 - 1;
int element1 = top1 / ELEMENT_HEIGHT;
int element2 = top2 / ELEMENT_HEIGHT;
listWidth = contentWidth;
listHeight = contentHeight;
synchronized(monitor)
{
label0:
{
int sel;
int press;
int count;
ChoiceElement[] list;
Font font;
if((count = this.count) <= 0)
{
render.setColor(RasterCanvas.getSystemColor(0x28));
render.setFont(font = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_SMALL));
render.drawString(MultilinedStringBuilder.truncate(emptyLabel, font, contentWidth), contentWidth >> 1, 0, Graphics.HCENTER | Graphics.TOP);
break label0;
}
if(type == POPUP)
{
boolean f = super.focused;
boolean p = pressed == 0;
int x;
int y;
Image icon;
ChoiceElement item = elements[selected];
render.setFont(font = item.font);
render.setColor(RasterCanvas.getSystemColor(f ? p ? 0x25 : 0x27 : 0x24));
render.drawElement(4, f ? p ? 1 : 3 : 0, 0, 0, 0, contentWidth, contentHeight);
if((icon = item.icon) != null)
{
x = MARGIN3 + (p ? 1 : 0);
y = ((ELEMENT_HEIGHT - font.getHeight()) >> 1) + (p ? 1 : 0);
render.drawStretch(icon, MARGIN + (p ? 1 : 0), ICON_TOP + (p ? 1 : 0), ICON_WIDTH, ICON_HEIGHT, 0);
render.drawString(MultilinedStringBuilder.truncate(item.text, font, contentWidth - (MARGIN * 2 + POPUP_ARROW_SIZE + MARGIN3)), x, y, 0);
} else
{
x = MARGIN + (p ? 1 : 0);
y = ((ELEMENT_HEIGHT - font.getHeight()) >> 1) + (p ? 1 : 0);
render.drawString(MultilinedStringBuilder.truncate(item.text, font, contentWidth - (MARGIN * 3 + POPUP_ARROW_SIZE)), x, y, 0);
}
x = contentWidth - (POPUP_ARROW_SIZE + MARGIN) + (p ? 1 : 0);
y = ((ELEMENT_HEIGHT - POPUP_ARROW_SIZE) >> 1) + (p ? 2 : 1);
render.fillTriangle(x, y, x + (POPUP_ARROW_SIZE - 1), y, x + (POPUP_ARROW_SIZE >> 1), y + (POPUP_ARROW_SIZE - 1));
break label0;
}
sel = super.focused ? selected : -1;
list = elements;
press = pressed;
render.translate(0, ELEMENT_HEIGHT * element1);
render.setColor(RasterCanvas.getSystemColor(0x28));
for(int i = element1; i <= element2 && i < count; render.translate(0, ELEMENT_HEIGHT), i++)
{
boolean check;
int textTop;
Image icon;
String text;
ChoiceElement item;
font = (item = list[i]).font;
icon = item.icon;
text = item.text;
check = item.selected;
textTop = (ELEMENT_HEIGHT - font.getHeight()) >> 1;
if(i == sel) render.drawElement(1, 0, 0, 0, 0, width, ELEMENT_HEIGHT);
render.setFont(font);
render.drawElement(type == EXCLUSIVE ? 12 : 15, check ? 1 : 0, i == press ? 1 : 0, MARGIN, CHECKBOX_TOP, CHECKBOX_WIDTH, CHECKBOX_HEIGHT);
if(icon != null)
{
render.drawStretch(icon, MARGIN1, MARGIN, ICON_WIDTH, ICON_HEIGHT, 0);
render.drawString(MultilinedStringBuilder.truncate(text, font, width - (MARGIN2 + MARGIN)), MARGIN2, textTop, 0);
} else
{
render.drawString(MultilinedStringBuilder.truncate(text, font, width - (MARGIN1 + MARGIN)), MARGIN1, textTop, 0);
}
}
}
}
}
void onCommandAction(Command command) {
if(command == SELECT_COMMAND)
{
synchronized(monitor)
{
showPopupMenu();
}
return;
}
if(command == CHECK_COMMAND)
{
synchronized(monitor)
{
int activeIndex;
int previousIndex;
switch(type)
{
case EXCLUSIVE:
if((activeIndex = selected) >= 0 && activeIndex < count && activeIndex != (previousIndex = checked))
{
ChoiceElement[] list;
(list = elements)[previousIndex].selected = false;
list[checked = activeIndex].selected = true;
super.notifyStateChanged();
super.requestPaint();
}
break;
case MULTIPLE:
if((activeIndex = selected) >= 0 && activeIndex < count)
{
ChoiceElement item;
(item = elements[activeIndex]).selected = !item.selected;
super.notifyStateChanged();
super.requestPaint();
}
break;
}
}
return;
}
if(command == MULTIPLE_ACTIONS[0])
{
synchronized(monitor)
{
boolean needRepaint = false;
ChoiceElement[] list = elements;
for(int i = count; i-- > 0; )
{
ChoiceElement item;
if(!(item = list[i]).selected)
{
needRepaint = true;
item.selected = true;
}
}
if(needRepaint)
{
super.notifyStateChanged();
super.requestPaint();
}
}
}
if(command == MULTIPLE_ACTIONS[1])
{
synchronized(monitor)
{
boolean needRepaint = false;
ChoiceElement[] list = elements;
for(int i = count; i-- > 0; )
{
ChoiceElement item;
if((item = list[i]).selected)
{
needRepaint = true;
item.selected = false;
}
}
if(needRepaint)
{
super.notifyStateChanged();
super.requestPaint();
}
}
}
if(command == MULTIPLE_ACTIONS[2])
{
synchronized(monitor)
{
int len;
if((len = count) > 0)
{
ChoiceElement[] list = elements;
for(int i = len; i-- > 0; )
{
ChoiceElement item;
(item = list[i]).selected = !item.selected;
}
super.notifyStateChanged();
super.requestPaint();
}
}
}
super.onCommandAction(command);
}
void onKeyboardEvent(KeyboardEvent event) {
int key = event.getKey();
DeviceSettings settings = DeviceManager.getInstance().getSettings();
if(key == settings.getKeyUsedAs(DeviceSettings.DEVICE_KEY_POUND))
{
if(event.getAction() == KeyboardEvent.ACTION_KEY_PRESSED)
{
Font font;
String text;
Display parent;
Displayable owner;
ChoiceElementViewer screen;
synchronized(screen = monitor)
{
if(count > 0)
{
ChoiceElement element;
text = (element = elements[selected]).text;
font = element.font;
} else
{
text = null;
font = null;
}
}
if(text != null && (owner = this.owner) != null && (parent = owner.getParentDisplay()) != null)
{
screen.getScrollBar().setPosition(0);
screen.setFont(font);
screen.setText(text);
parent.setCurrent(screen);
}
}
return;
}
if(key == KeyboardEvent.KEY_SPACE)
{
switch(event.getAction())
{
case KeyboardEvent.ACTION_KEY_PRESSED:
pressed = type == POPUP ? 0 : selected;
requestPaint();
break;
case KeyboardEvent.ACTION_KEY_RELEASED:
switch(type)
{
case POPUP:
synchronized(monitor)
{
if(count > 0) showPopupMenu();
}
break;
case EXCLUSIVE:
synchronized(monitor)
{
int activeIndex;
int previousIndex;
ChoiceElement[] list;
if((activeIndex = pressed) >= 0 && activeIndex < count && activeIndex != (previousIndex = checked))
{
(list = elements)[previousIndex].selected = false;
list[checked = activeIndex].selected = true;
super.notifyStateChanged();
}
}
break;
case MULTIPLE:
synchronized(monitor)
{
int activeIndex;
ChoiceElement item;
if((activeIndex = pressed) >= 0 && activeIndex < count)
{
(item = elements[activeIndex]).selected = !item.selected;
super.notifyStateChanged();
}
}
break;
}
pressed = -1;
requestPaint();
break;
}
}
}
void onPointerEvent(PointerEvent event) {
int c;
int f;
int i;
int y;
switch(event.getAction())
{
case PointerEvent.ACTION_BUTTON_PRESSED:
case PointerEvent.ACTION_POINTER_PRESSED:
if(event.getButton() == PointerEvent.BUTTON_MAIN)
{
if(type == POPUP)
{
if((focused = getFocusedElement(event.getX(), event.getY())) == -2)
{
pressed = 0;
requestPaint();
}
break;
}
if((focused = f = getFocusedElement(event.getX(), y = event.getY())) >= 0)
{
pressed = f;
synchronized(monitor)
{
c = count;
if((i = f) >= c) i = c - 1;
if(i < 0) i = 0;
selected = i;
requestInvalidate();
}
break;
}
if(f == -2) synchronized(monitor)
{
c = count;
if((i = y / ELEMENT_HEIGHT) >= c) i = c - 1;
if(i < 0) i = 0;
if(selected != i)
{
selected = i;
requestInvalidate();
}
}
}
break;
case PointerEvent.ACTION_POINTER_DRAGGED:
if(type == POPUP)
{
if(focused == -2 && pressed != (pressed = getFocusedElement(event.getX(), event.getY()) == -2 ? 0 : -1)) requestPaint();
break;
}
if((f = focused) >= 0)
{
if(pressed != (pressed = getFocusedElement(event.getX(), event.getY()) == f ? f : -1)) requestPaint();
break;
}
if(f == -2) synchronized(monitor)
{
c = count;
if((i = event.getY() / ELEMENT_HEIGHT) >= c) i = c - 1;
if(i < 0) i = 0;
if(selected != i)
{
selected = i;
requestInvalidate();
}
}
break;
case PointerEvent.ACTION_POINTER_RELEASED:
case PointerEvent.ACTION_BUTTON_RELEASED:
if(event.getButton() == PointerEvent.BUTTON_MAIN && (f = focused) != -1)
{
int p = pressed;
focused = -1;
pressed = -1;
if(type == POPUP)
{
if(f == -2 && p == 0) synchronized(monitor)
{
if(count > 0)
{
showPopupMenu();
} else
{
requestPaint();
}
}
break;
}
synchronized(monitor)
{
if(f == -2)
{
c = count;
if((i = event.getY() / ELEMENT_HEIGHT) >= c) i = c - 1;
if(i < 0) i = 0;
if(selected != i)
{
selected = i;
requestInvalidate();
}
}
if(p >= 0)
{
int s;
switch(type)
{
case EXCLUSIVE:
if(p < count && p != (s = checked))
{
ChoiceElement[] list;
(list = elements)[s].selected = false;
list[checked = p].selected = true;
super.notifyStateChanged();
}
break;
case MULTIPLE:
if(p < count)
{
ChoiceElement item;
(item = elements[p]).selected = !item.selected;
super.notifyStateChanged();
}
break;
}
}
}
requestPaint();
}
break;
}
}
void onFocusLost() {
focused = -1;
pressed = -1;
super.onFocusLost();
}
boolean onFocusMove(int direction, int viewportWidth, int viewportHeight, int[] visibleRectangle) {
boolean stay;
int elementIndex;
if(!super.onFocusMove(direction, viewportWidth, viewportHeight, visibleRectangle))
{
elementIndex = 0;
if(type != POPUP) synchronized(monitor)
{
if(direction == DIR_UP)
{
int len;
if((len = count) > 0) selected = elementIndex = len - 1;
} else
{
selected = 0;
}
}
visibleRectangle[LEFT] = 0;
visibleRectangle[TOP] = elementIndex * ELEMENT_HEIGHT;
visibleRectangle[WIDTH] = listWidth;
visibleRectangle[HEIGHT] = ELEMENT_HEIGHT;
return true;
}
if(type == POPUP) return false;
switch(direction)
{
case DIR_NONE:
elementIndex = selected;
break;
case DIR_UP:
synchronized(monitor)
{
if(stay = (elementIndex = selected) > 0) selected = --elementIndex;
}
if(!stay) return false;
requestPaint();
break;
case DIR_DOWN:
synchronized(monitor)
{
if(stay = (elementIndex = selected) < count - 1) selected = ++elementIndex;
}
if(!stay) return false;
requestPaint();
break;
default:
return false;
}
visibleRectangle[LEFT] = 0;
visibleRectangle[TOP] = elementIndex * ELEMENT_HEIGHT;
visibleRectangle[WIDTH] = listWidth;
visibleRectangle[HEIGHT] = ELEMENT_HEIGHT;
return true;
}
int getMinimumContentWidth() {
return 100;
}
int getMinimumContentHeight() {
return ELEMENT_HEIGHT * (type == POPUP ? 1 : Math.max(1, count));
}
final void setSelected(int elementIndex) {
synchronized(monitor)
{
int lim;
if(elementIndex > (lim = count - 1)) elementIndex = lim;
if(elementIndex < 0) elementIndex = 0;
if(selected != elementIndex)
{
selected = elementIndex;
super.notifyStateChanged();
super.requestPaint();
}
}
}
private void showPopupMenu() {
int position;
int len = count;
ChoiceElement[] list;
ChoiceList menu;
ScrollBar scroll;
Display parent;
Screen screen;
if((screen = owner) == null || (parent = screen.getParentDisplay()) == null) return;
position = (scroll = (menu = popupMenu).getScrollBar()).getPosition();
menu.deleteAll();
list = elements;
for(int i = 0; i < len; i++)
{
ChoiceElement item = list[i];
menu.append(item.text, item.icon, item.font);
}
if(len > 0) menu.setSelectedIndex(selected);
scroll.setPosition(position);
parent.setCurrent(menu);
}
private int getFocusedElement(int x, int y) {
return x >= 0 && x < listWidth && y >= 0 && y < listHeight ? type != POPUP && x < MARGIN1 ? y / ELEMENT_HEIGHT : -2 : -1;
}
private ChoiceList createPopupMenu() {
ChoiceList result;
final Command select = SELECT_COMMAND;
Command back = new Command("Назад", Command.BACK, 0);
(result = new ChoiceList(null, null)).setCommandListener(new CommandListener() {
public void commandAction(Command command, Displayable screen) {
Display parent;
if(command == select) (ChoiceGroup.this).setSelected(((TextMenu) screen).getSelectedIndex());
if((parent = screen.getParentDisplay()) != null) parent.hideForeground();
}
});
result.addCommand(select);
result.addCommand(back);
return result;
}
}