/*
Реализация спецификаций 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 java.lang.ref.*;
import malik.emulator.media.graphics.*;
public class ChoiceGroup extends Item
implements Choice
{
private static final class Element extends ChoiceElement
{
public boolean visible;
public int top;
public int bottom;
public String truncated;
Element(boolean selected, Font font, String text, Image icon)
{
super(selected, font, text, icon);
}
public int getWidth()
{
return List.CHECKBOX_WIDTH + font.stringWidth(text) + (icon != null ? 36 : 9);
}
public int getHeight()
{
return Math.max(icon != null ? 24 : 0,
Math.max(font.getHeight(), List.CHECKBOX_HEIGHT)) + 6;
}
}
private static final class PopupCommandHandler extends WeakReference
implements CommandListener
{
PopupCommandHandler(ChoiceGroup thisItem)
{
super(thisItem);
}
public void commandAction(Command command, Displayable screen)
{
int i;
int f;
List list;
ChoiceGroup thisItem;
if((thisItem = (ChoiceGroup) get()) == null || screen != (list = thisItem.popupList))
{
return;
}
if(command == List.SELECT_COMMAND)
{
synchronized(thisItem.lock)
{
i = thisItem.focusedElementIndex;
f = thisItem.focusedElementIndex = Math.max(list.getSelectedIndex(), 0);
thisItem.showSourceScreen();
if(i != f)
{
thisItem.invokeNotifyStateChanged();
}
}
return;
}
if(command == BACK)
{
synchronized(thisItem.lock)
{
thisItem.showSourceScreen();
}
}
}
}
private static final Command[] SELECT;
private static final Command BACK;
private static final Command POPUP_COMMAND;
private static final String POPUP_LABEL = "Выбрать…";
static
{
SELECT = new Command[] {
new Command("Отметить все", Command.ITEM, 0),
new Command("Снять все", Command.ITEM, 0),
new Command("Переключить все", Command.ITEM, 0)
};
BACK = new Command("Назад", Command.BACK, 0);
POPUP_COMMAND = new Command(POPUP_LABEL, Command.OK, 0);
}
private boolean controlFocused;
private int type;
private int fitPolicy;
private int contentWidth;
private int contentHeight;
private int checkboxFocused;
private int checkboxPressed;
private int checkedElementIndex;
private int focusedElementIndex;
private int elementsCount;
private Element[] elements;
private Command selectCommand;
private List popupList;
private Displayable sourceScreen;
private Object lock;
public ChoiceGroup(String label, int type)
{
this(LAYOUT_DEFAULT, label, null, null, type, new String[0], null);
}
public ChoiceGroup(String label, int type, String[] elements, Image[] icons)
{
this(LAYOUT_DEFAULT, label, null, null, type, elements, icons);
}
public ChoiceGroup(int layout, String label,
Command[] commands, ItemCommandListener listener,
int type, String[] elements, Image[] icons)
{
super(layout, -1, -1, label,
type == MULTIPLE ? Displayable.concatCommands(SELECT, commands) : commands,
elements == null || elements.length == 0 ? null :
type == POPUP ? POPUP_COMMAND : List.CHECK_COMMAND, listener);
int i;
int len;
String[] lines;
Element[] list;
Command[] popupCommands;
Font font;
if(type != EXCLUSIVE && type != MULTIPLE && type != POPUP)
{
throw new IllegalArgumentException("ChoiceGroup: " +
"недопустимое значение параметра type.");
}
if(elements == null)
{
throw new NullPointerException("ChoiceGroup: " +
"параметр elements равен нулевой ссылке.");
}
Array.copy(elements, 0, lines = new String[len = elements.length], 0, len);
for(i = len; i-- > 0; )
{
if(lines[i] == null)
{
throw new NullPointerException("ChoiceGroup: " +
"параметр elements содержит нулевые ссылки.");
}
}
if(icons != null && icons.length != len)
{
throw new IllegalArgumentException("ChoiceGroup: " +
"параметр icons имеет длину, отличную от длины параметра elements.");
}
font = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL);
for(list = new Element[i = len]; i-- > 0; )
{
list[i] = new Element(type == EXCLUSIVE && i == 0, font,
lines[i], icons == null ? null : icons[i]);
}
popupCommands = new Command[] {
BACK
};
this.type = type;
this.fitPolicy = TEXT_WRAP_DEFAULT;
this.checkboxFocused = -1;
this.checkboxPressed = -1;
this.checkedElementIndex = 0;
this.focusedElementIndex = 0;
this.elementsCount = len;
this.elements = list;
this.selectCommand = type != POPUP ? List.CHECK_COMMAND : POPUP_COMMAND;
this.popupList = type != POPUP ? null : new List(false, POPUP_LABEL, null,
popupCommands, List.SELECT_COMMAND, new PopupCommandHandler(this),
IMPLICIT, elements, icons);
this.lock = new Object();
}
public void setFitPolicy(int policy)
{
if(policy != TEXT_WRAP_DEFAULT && policy != TEXT_WRAP_ON && policy != TEXT_WRAP_OFF)
{
throw new IllegalArgumentException("ChoiceGroup.setFitPolicy: " +
"недопустимое значение параметра policy.");
}
this.fitPolicy = policy;
}
public void setSelectedIndex(int elementIndex, boolean selected)
{
int error;
int checked;
Element[] list;
Element elem;
Element prev;
error = 0;
synchronized(lock)
{
label0:
{
if(elementIndex < 0 || elementIndex >= elementsCount)
{
error = 1;
break label0;
}
switch(type)
{
case EXCLUSIVE:
if(elementIndex != (checked = checkedElementIndex))
{
checkedElementIndex = elementIndex;
(elem = (list = elements)[elementIndex]).selected = true;
(prev = list[checked]).selected = false;
if(elem.visible || prev.visible)
{
notifyPaint();
}
}
break;
case MULTIPLE:
if((elem = elements[elementIndex]).selected != selected)
{
elem.selected = selected;
if(elem.visible)
{
notifyPaint();
}
}
break;
case POPUP:
if(elementIndex != focusedElementIndex)
{
focusedElementIndex = elementIndex;
notifyPaint();
}
break;
}
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("ChoiceGroup.setSelectedIndex: " +
"параметр elementIndex выходит из диапазона.");
}
}
public void setSelectedFlags(boolean[] selected)
{
boolean sel;
boolean needRepaint;
int i;
int len;
int error;
int checked;
int elementIndex;
Element[] list;
Element elem;
Element prev;
if(selected == null)
{
throw new NullPointerException("ChoiceGroup.setSelectedFlags: " +
"параметр selected равен нулевой ссылке.");
}
error = 0;
synchronized(lock)
{
label0:
{
if(selected.length < (len = elementsCount))
{
error = 1;
break label0;
}
switch(type)
{
case EXCLUSIVE:
elementIndex = -1;
for(i = 0; i < len; i++)
{
if(selected[i] == false)
{
continue;
}
elementIndex = i;
break;
}
if(elementIndex < 0)
{
break;
}
if(elementIndex != (checked = checkedElementIndex))
{
checkedElementIndex = elementIndex;
(elem = (list = elements)[elementIndex]).selected = true;
(prev = list[checked]).selected = false;
if(elem.visible || prev.visible)
{
notifyPaint();
}
}
break;
case MULTIPLE:
needRepaint = false;
list = elements;
for(i = len; i-- > 0; )
{
if((elem = list[i]).selected == (sel = selected[i]))
{
continue;
}
elem.selected = sel;
if(elem.visible)
{
needRepaint = true;
}
}
if(needRepaint)
{
notifyPaint();
}
break;
case POPUP:
elementIndex = -1;
for(i = 0; i < len; i++)
{
if(selected[i] == false)
{
continue;
}
elementIndex = i;
break;
}
if(elementIndex < 0)
{
break;
}
if(elementIndex != focusedElementIndex)
{
focusedElementIndex = elementIndex;
notifyPaint();
}
break;
}
}
}
if(error == 1)
{
throw new IllegalArgumentException("ChoiceGroup.setSelectedFlags: " +
"длина параметра selected меньше количества элементов списка.");
}
}
public void setFont(int elementIndex, Font font)
{
int error;
Font f;
Element elem;
f = font != null ? font :
Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL);
error = 0;
synchronized(lock)
{
label0:
{
if(elementIndex < 0 || elementIndex >= elementsCount)
{
error = 1;
break label0;
}
if(f != (elem = elements[elementIndex]).font)
{
elem.font = f;
correctTruncated(elem);
if(type == POPUP)
{
popupList.setFont(elementIndex, font);
}
notifyUpdate();
}
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("ChoiceGroup.setFont: " +
"параметр elementIndex выходит из диапазона.");
}
}
public void set(int elementIndex, String text, Image icon)
{
int error;
Element elem;
if(text == null)
{
throw new NullPointerException("ChoiceGroup.set: " +
"параметр text равен нулевой ссылке.");
}
error = 0;
synchronized(lock)
{
label0:
{
if(elementIndex < 0 || elementIndex >= elementsCount)
{
error = 1;
break label0;
}
(elem = elements[elementIndex]).text = text;
elem.icon = icon;
correctTruncated(elem);
if(type == POPUP)
{
popupList.set(elementIndex, text, icon);
}
notifyUpdate();
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("ChoiceGroup.set: " +
"параметр elementIndex выходит из диапазона.");
}
}
public void insert(int elementIndex, String text, Image icon)
{
int t;
int i;
int len;
int error;
Element[] list;
if(text == null)
{
throw new NullPointerException("ChoiceGroup.insert: " +
"параметр text равен нулевой ссылке.");
}
error = 0;
synchronized(lock)
{
label0:
{
if(elementIndex < 0 || elementIndex > (len = elementsCount))
{
error = 1;
break label0;
}
if(len == (list = elements).length)
{
Array.copy(list, 0, list = elements = new Element[(len << 1) + 1], 0, len);
}
if((i = len - elementIndex) > 0)
{
Array.copy(list, elementIndex, list, elementIndex + 1, i);
}
list[elementIndex] = new Element((t = type) == EXCLUSIVE && len == 0,
Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL),
text, icon);
elementsCount = ++len;
checkboxPressed = -1;
checkboxFocused = -1;
if(len > 1)
{
if((i = checkedElementIndex) >= elementIndex)
{
checkedElementIndex = i + 1;
}
if((i = focusedElementIndex) >= elementIndex)
{
focusedElementIndex = i + 1;
}
} else
{
super.setDefaultCommand(selectCommand);
}
if(t == POPUP)
{
popupList.insert(elementIndex, text, icon);
}
notifyUpdate();
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("ChoiceGroup.insert: " +
"параметр elementIndex выходит из диапазона.");
}
}
public void delete(int elementIndex)
{
int t;
int i;
int len;
int error;
Element[] list;
error = 0;
synchronized(lock)
{
label0:
{
if(elementIndex < 0 || elementIndex >= (len = elementsCount))
{
error = 1;
break label0;
}
list = elements;
if((i = len - elementIndex - 1) > 0)
{
Array.copy(list, elementIndex + 1, list, elementIndex, i);
}
list[--len] = null;
elementsCount = len;
checkboxPressed = -1;
checkboxFocused = -1;
t = type;
if(len > 0)
{
label1:
{
if((i = checkedElementIndex) > elementIndex)
{
checkedElementIndex = i - 1;
break label1;
}
if(i == elementIndex)
{
checkedElementIndex = i = i == len ? i - 1 : i;
if(t == EXCLUSIVE)
{
list[i].selected = true;
}
}
}
if((i = focusedElementIndex) == elementIndex && i == len || i > elementIndex)
{
focusedElementIndex = i - 1;
}
} else
{
super.removeCommand(selectCommand);
}
if(t == POPUP)
{
popupList.delete(elementIndex);
}
notifyUpdate();
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("ChoiceGroup.delete: " +
"параметр elementIndex выходит из диапазона.");
}
}
public void deleteAll()
{
int i;
int len;
Element[] list;
synchronized(lock)
{
if((len = elementsCount) > 0)
{
for(list = elements, i = len; i-- > 0; list[i] = null);
elementsCount = 0;
checkboxPressed = -1;
checkboxFocused = -1;
checkedElementIndex = 0;
focusedElementIndex = 0;
super.removeCommand(selectCommand);
if(type == POPUP)
{
popupList.deleteAll();
}
notifyUpdate();
}
}
}
public boolean isSelected(int elementIndex)
{
boolean result = false;
int error = 0;
synchronized(lock)
{
label0:
{
if(elementIndex < 0 || elementIndex >= elementsCount)
{
error = 1;
break label0;
}
switch(type)
{
case EXCLUSIVE:
result = checkedElementIndex == elementIndex;
break;
case MULTIPLE:
result = elements[elementIndex].selected;
break;
case POPUP:
result = focusedElementIndex == elementIndex;
break;
}
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("ChoiceGroup.isSelected: " +
"параметр elementIndex выходит из диапазона.");
}
return result;
}
public int append(String text, Image icon)
{
int t;
int len;
int result;
Element[] list;
if(text == null)
{
throw new NullPointerException("ChoiceGroup.append: " +
"параметр text равен нулевой ссылке.");
}
synchronized(lock)
{
if((len = elementsCount) == (list = elements).length)
{
Array.copy(list, 0, list = elements = new Element[(len << 1) + 1], 0, len);
}
list[result = len] = new Element((t = type) == EXCLUSIVE && len == 0,
Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL),
text, icon);
elementsCount = ++len;
checkboxPressed = -1;
checkboxFocused = -1;
if(len == 1)
{
super.setDefaultCommand(selectCommand);
}
if(t == POPUP)
{
popupList.append(text, icon);
}
notifyUpdate();
}
return result;
}
public int size()
{
return elementsCount;
}
public int getFitPolicy()
{
return fitPolicy;
}
public int getSelectedIndex()
{
if(elementsCount == 0)
{
return -1;
}
switch(type)
{
default:
return -1;
case EXCLUSIVE:
return checkedElementIndex;
case POPUP:
return focusedElementIndex;
}
}
public int getSelectedFlags(boolean[] selected)
{
int f;
int i;
int len;
int error;
int result;
Element[] list;
if(selected == null)
{
throw new NullPointerException("ChoiceGroup.getSelectedFlags: " +
"параметр selected равен нулевой ссылке.");
}
result = 0;
error = 0;
synchronized(lock)
{
label0:
{
if(selected.length < (len = elementsCount))
{
error = 1;
break label0;
}
switch(type)
{
case EXCLUSIVE:
result = len > 0 ? 1 : 0;
f = checkedElementIndex;
for(i = len; i-- > 0; selected[i] = i == f);
break;
case MULTIPLE:
result = 0;
list = elements;
for(i = len; i-- > 0; )
{
if(selected[i] = list[i].selected)
{
result++;
}
}
break;
case POPUP:
result = len > 0 ? 1 : 0;
f = focusedElementIndex;
for(i = len; i-- > 0; selected[i] = i == f);
break;
}
}
}
if(error == 1)
{
throw new IllegalArgumentException("ChoiceGroup.getSelectedFlags: " +
"длина параметра selected меньше количества элементов списка.");
}
return result;
}
public Font getFont(int elementIndex)
{
int error;
Font result;
error = 0;
synchronized(lock)
{
label0:
{
if(elementIndex < 0 || elementIndex >= elementsCount)
{
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;
Image result;
error = 0;
synchronized(lock)
{
label0:
{
if(elementIndex < 0 || elementIndex >= elementsCount)
{
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;
String result;
error = 0;
synchronized(lock)
{
label0:
{
if(elementIndex < 0 || elementIndex >= elementsCount)
{
error = 1;
result = null;
break label0;
}
result = elements[elementIndex].text;
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("ChoiceGroup.getString: " +
"параметр elementIndex выходит из диапазона.");
}
return result;
}
void paintContent(Graphics render, int contentWidth, int contentHeight)
{
boolean cfocused;
int s;
int x;
int y;
int t;
int i;
int len;
int top;
int bottom;
int pressed;
int focused;
int elementHeight;
int leftMarginCheckbox;
int leftMarginIcon;
int leftMarginText;
int topMarginCheckbox;
int topMarginElement;
Element[] list;
Element elem;
Image icon;
Font font;
synchronized(lock)
{
cfocused = controlFocused;
pressed = checkboxPressed;
focused = focusedElementIndex;
len = elementsCount;
list = elements;
if((t = type) == POPUP)
{
if(len > 0)
{
render.setColor(RasterCanvas.getSystemColor(
(i = cfocused ? (pressed >= 0 ? 1 : 3) : 0) + 0x24));
render.drawElementOfGUI(4, i, 0, 0, 0, contentWidth, contentHeight);
i = i == 1 ? 1 : 0;
if((icon = (elem = list[focused]).icon) == null)
{
leftMarginText = 3;
} else
{
leftMarginText = 30;
render.drawStretchRegion(icon, 0, 0, icon.getWidth(), icon.getHeight(), 0,
i + 3, i + ((contentHeight - 24) >> 1), 24, 24, 0);
}
render.setFont(font = elem.font);
render.drawString(elem.truncated, i + leftMarginText,
i + ((contentHeight - font.getHeight()) >> 1), 0);
s = List.CHECKBOX_WIDTH > 7 ? 7 : ((List.CHECKBOX_WIDTH - 1) & 1) + 1;
x = i + contentWidth - s - 3;
y = i + ((contentHeight - s) >> 1) + 2;
for(i = s; i-- > 0; y++)
{
render.drawLine(x, y, x + s - 1, y);
if((i & 1) == 0)
{
x++;
s -= 2;
}
}
}
} else
{
bottom = (top = render.getClipY()) + render.getClipHeight();
leftMarginText = (leftMarginIcon = (leftMarginCheckbox = 3) +
List.CHECKBOX_WIDTH + 3) + 27;
topMarginElement = 0;
for(i = 0; i < len; render.translate(0, elementHeight),
topMarginElement += elementHeight, i++)
{
elementHeight = (elem = list[i]).getHeight();
elem.top = topMarginElement;
elem.bottom = topMarginElement + elementHeight;
if(!(elem.visible = topMarginElement < bottom &&
topMarginElement + elementHeight > top))
{
continue;
}
if(cfocused && i == focused)
{
render.drawElementOfGUI(1, 0, 0, 0, 0, contentWidth, elementHeight);
}
topMarginCheckbox = (elementHeight - List.CHECKBOX_HEIGHT) >> 1;
switch(t)
{
case EXCLUSIVE:
render.drawElementOfGUI(12,
elem.selected ? 1 : 0, i == pressed ? 1 : 0,
leftMarginCheckbox, topMarginCheckbox,
List.CHECKBOX_WIDTH, List.CHECKBOX_HEIGHT);
break;
case MULTIPLE:
render.drawElementOfGUI(15,
elem.selected ? 1 : 0, i == pressed ? 1 : 0,
leftMarginCheckbox, topMarginCheckbox,
List.CHECKBOX_WIDTH, List.CHECKBOX_HEIGHT);
break;
}
if((icon = elem.icon) != null)
{
render.drawStretchRegion(icon, 0, 0, icon.getWidth(), icon.getHeight(), 0,
leftMarginIcon, (elementHeight - 24) >> 1, 24, 24, 0);
}
render.setFont(font = elem.font);
render.drawString(elem.truncated,
icon != null ? leftMarginText : leftMarginIcon,
(elementHeight - font.getHeight()) >> 1, 0);
}
}
}
}
void onSizeChanged(int contentWidth, int contentHeight)
{
int i;
Element[] list;
this.contentWidth = contentWidth;
this.contentHeight = contentHeight;
synchronized(lock)
{
for(list = elements, i = elementsCount; i-- > 0; correctTruncated(list[i]));
}
}
void onKeyPressed(int key, int charCode)
{
int i;
MIDletProxy proxy;
if(key == (proxy = MIDletProxy.getInstance()).getKeyUsedAs(MIDletProxy.DEVICE_KEY_POUND))
{
synchronized(lock)
{
if((i = focusedElementIndex) >= 0 && i < elementsCount)
{
ChoiceElementDetailsScreen.show(proxy.getEmulatorScreen(),
super.getLabel(), elements[i], getOwner());
}
}
}
}
void onContentPointerPressed(int x, int y, int button)
{
int i;
synchronized(lock)
{
if(button == MIDletProxy.BUTTON_MAIN && (i = getElementIndex(x, y)) >= 0)
{
if(type == POPUP || x < List.CHECKBOX_WIDTH + 6)
{
checkboxFocused = i;
checkboxPressed = i;
}
focusedElementIndex = i;
notifyPaint();
}
}
}
void onContentPointerDragged(int x, int y)
{
int i;
int f;
synchronized(lock)
{
if((f = checkboxFocused) >= 0)
{
if(checkboxPressed != (checkboxPressed = f == (type == POPUP ||
x < List.CHECKBOX_WIDTH + 6 ? getElementIndex(x, y) : -1) ? f : -1))
{
notifyPaint();
}
}
else if((i = getElementIndex(x, y)) >= 0)
{
focusedElementIndex = i;
notifyPaint();
}
}
}
void onContentPointerReleased(int x, int y, int button)
{
int i;
int f;
Element[] list;
Element elem;
synchronized(lock)
{
if(button == MIDletProxy.BUTTON_MAIN)
{
f = checkboxPressed;
checkboxFocused = -1;
checkboxPressed = -1;
if(f >= 0 && f < elementsCount)
{
switch(type)
{
case EXCLUSIVE:
(list = elements)[i = checkedElementIndex].selected = false;
list[checkedElementIndex = f].selected = true;
notifyPaint();
if(i != f)
{
super.notifyStateChanged();
}
break;
case MULTIPLE:
(elem = elements[f]).selected = !elem.selected;
notifyPaint();
super.notifyStateChanged();
break;
case POPUP:
showPopupList();
break;
}
}
}
}
}
void onCommandAction(Command command)
{
boolean need;
int i;
int f;
Element[] list;
Element elem;
if(command == SELECT[0])
{
synchronized(lock)
{
need = false;
for(list = elements, i = elementsCount; i-- > 0; )
{
if(!(elem = list[i]).selected)
{
need = true;
elem.selected = true;
}
}
if(need)
{
notifyPaint();
super.notifyStateChanged();
}
}
return;
}
if(command == SELECT[1])
{
synchronized(lock)
{
need = false;
for(list = elements, i = elementsCount; i-- > 0; )
{
if((elem = list[i]).selected)
{
need = true;
elem.selected = false;
}
}
if(need)
{
notifyPaint();
super.notifyStateChanged();
}
}
return;
}
if(command == SELECT[2])
{
synchronized(lock)
{
need = false;
for(list = elements, i = elementsCount; i-- > 0; )
{
need = true;
(elem = list[i]).selected = !elem.selected;
}
if(need)
{
notifyPaint();
super.notifyStateChanged();
}
}
return;
}
if(command == POPUP_COMMAND)
{
synchronized(lock)
{
showPopupList();
}
return;
}
if(command == List.CHECK_COMMAND)
{
synchronized(lock)
{
if((f = focusedElementIndex) >= 0 && f < elementsCount)
{
switch(type)
{
case EXCLUSIVE:
(list = elements)[i = checkedElementIndex].selected = false;
list[checkedElementIndex = f].selected = true;
notifyPaint();
if(i != f)
{
super.notifyStateChanged();
}
break;
case MULTIPLE:
(elem = elements[f]).selected = !elem.selected;
notifyPaint();
super.notifyStateChanged();
break;
}
}
}
return;
}
super.onCommandAction(command);
}
void onTraverseOut()
{
controlFocused = false;
notifyPaint();
}
boolean onTraverseNeedStayOn(int direction, int viewportWidth, int viewportHeight,
int[] visibleRectangle)
{
boolean result;
boolean cfocused;
int labelHeight;
int focused;
int tmp;
int elt;
int elh;
int vrt;
int vrh;
Element elem;
if((cfocused = controlFocused) != (controlFocused = true))
{
notifyPaint();
}
if(checkboxFocused >= 0)
{
return true;
}
switch(direction)
{
case Canvas.LEFT:
case Canvas.RIGHT:
if(type == POPUP)
{
return !cfocused;
}
labelHeight = super.getPreferredHeight() - contentHeight;
if(!cfocused)
{
synchronized(lock)
{
focused = focusedElementIndex;
if((vrh = visibleRectangle[HEIGHT]) < (elh =
(elem = elements[focused]).getHeight()))
{
visibleRectangle[HEIGHT] = vrh = elh;
}
if((vrt = visibleRectangle[TOP]) > (tmp = labelHeight + (elt = elem.top)))
{
visibleRectangle[TOP] = tmp;
}
else if(vrt < (tmp = labelHeight + elt + elh - vrh))
{
visibleRectangle[TOP] = tmp;
}
notifyPaint();
}
return true;
}
return false;
case Canvas.UP:
if(type == POPUP)
{
return !cfocused;
}
labelHeight = super.getPreferredHeight() - contentHeight;
synchronized(lock)
{
if(result = cfocused ? (focused = focusedElementIndex) > 0 :
(focused = elementsCount) > 0)
{
focusedElementIndex = --focused;
if((vrt = visibleRectangle[TOP]) > (tmp =
labelHeight + (elem = elements[focused]).top))
{
visibleRectangle[TOP] = tmp;
}
else if(vrt < (tmp =
labelHeight + elem.bottom - visibleRectangle[HEIGHT]))
{
visibleRectangle[TOP] = tmp;
}
notifyPaint();
}
}
return result;
case Canvas.DOWN:
if(type == POPUP)
{
return !cfocused;
}
labelHeight = super.getPreferredHeight() - contentHeight;
synchronized(lock)
{
if(result = cfocused ? (focused = focusedElementIndex) < elementsCount - 1 :
elementsCount > (focused = -1) + 1)
{
focusedElementIndex = ++focused;
if((vrt = visibleRectangle[TOP]) > (tmp =
labelHeight + (elem = elements[focused]).top))
{
visibleRectangle[TOP] = tmp;
}
else if(vrt < (tmp =
labelHeight + elem.bottom - visibleRectangle[HEIGHT]))
{
visibleRectangle[TOP] = tmp;
}
notifyPaint();
}
}
return result;
}
return true;
}
boolean keyHandling(int key)
{
return key == MIDletProxy.getInstance().getKeyUsedAs(MIDletProxy.DEVICE_KEY_POUND);
}
int getPreferredContentWidth(int contentHeight, int containerClientWidth)
{
int i;
int tmp;
int result = 0;
Element[] list;
synchronized(lock)
{
for(list = elements, i = elementsCount; i-- > 0; )
{
if(result < (tmp = list[i].getWidth()))
{
result = tmp;
}
}
}
return result < containerClientWidth ? result : containerClientWidth;
}
int getPreferredContentHeight(int contentWidth)
{
int i;
int tmp;
int result = 0;
Element[] list;
synchronized(lock)
{
if(type == POPUP)
{
for(list = elements, i = elementsCount; i-- > 0; )
{
if(result < (tmp = list[i].getHeight()))
{
result = tmp;
}
}
} else
{
for(list = elements, i = elementsCount; i-- > 0; )
{
result += list[i].getHeight();
}
}
}
return result;
}
private void showPopupList()
{
int i;
List screen;
if((screen = popupList) != null && (sourceScreen = getOwner()) != null)
{
if((i = focusedElementIndex) >= 0 && i < screen.size())
{
screen.setSelectedIndex(i, true);
}
MIDletProxy.getInstance().getEmulatorScreen().setCurrent(screen);
}
}
private void showSourceScreen()
{
Displayable next;
Display display = MIDletProxy.getInstance().getEmulatorScreen();
if((next = sourceScreen).isSystem())
{
display.setCurrent(next);
} else
{
display.hideSystemScreen();
}
sourceScreen = null;
}
private void invokeNotifyStateChanged()
{
super.notifyStateChanged();
}
private void correctTruncated(Element elem)
{
int t;
elem.truncated = Displayable.truncate(elem.text, elem.font, contentWidth -
((t = type) != POPUP ? List.CHECKBOX_WIDTH + 3 : 0) -
(elem.icon != null ? 27 : 0) - (t == POPUP ? 16 : 6));
}
private int getElementIndex(int x, int y)
{
int a;
int b;
int c;
Element[] list;
Element elem;
if(x < 0 || x >= contentWidth || y < 0 || y >= contentHeight)
{
return -1;
}
if(type == POPUP)
{
return focusedElementIndex;
}
a = 0;
b = elementsCount - 1;
list = elements;
while(a <= b)
{
elem = list[c = (a + b) >> 1];
if(y < elem.top)
{
b = c - 1;
continue;
}
if(y >= elem.bottom)
{
a = c + 1;
continue;
}
return c;
}
return -1;
}
}