/*
Реализация спецификаций 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 malik.emulator.microedition.lcdui;
import javax.microedition.lcdui.*;
import malik.emulator.application.*;
import malik.emulator.media.graphics.*;
import malik.emulator.microedition.*;
import malik.emulator.util.*;
public class StringList extends CustomSurfaceScreen implements TextMenu
{
private static final int INITIAL_SCROLL = 32;
private int selected;
private int scroll;
private int count;
private String[] elements;
private Font font;
private final Object monitor;
public StringList(String title, ScrollBarStyle style) {
this(title, style, null);
}
public StringList(String title, ScrollBarStyle style, String[] list) {
super(title, 0, true, style);
int length;
String[] elements = new String[(length = list == null ? 0 : list.length) <= 0x0f ? 0x0f : StringBuilder.optimalCapacity(length)];
Font font = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_SMALL);
for(int i = length; i-- > 0; )
{
String s;
elements[i] = (s = list[i]) == null ? "" : s;
}
this.scroll = INITIAL_SCROLL;
this.count = length;
this.elements = elements;
this.font = font;
this.monitor = new Object();
super.getScrollBar().setRange(font.getHeight() * length);
}
public void insert(int elementIndex, String text) {
if(text == null) text = "";
synchronized(monitor)
{
int sel;
int len;
String[] list;
if(elementIndex > (len = count)) elementIndex = len;
if(elementIndex < 0) elementIndex = 0;
if(len == (list = elements).length) Array.copy(list, 0, list = elements = new String[(len << 1) + 1], 0, len);
if(elementIndex < len) Array.copy(list, elementIndex, list, elementIndex + 1, len - elementIndex);
list[elementIndex] = text;
count = ++len;
sel = selected;
if(len > 1 && sel >= elementIndex) selected = ++sel;
super.getScrollBar().setRange(font.getHeight() * len);
correctScrollBarPosition(sel);
}
}
public void delete(int elementIndex) {
int error = 0;
synchronized(monitor)
{
label0:
{
int sel;
int len;
String[] list;
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[count = len] = null;
sel = selected;
if(len > 0)
{
if(sel == elementIndex)
{
if(sel >= len) sel = len - 1;
selected = sel;
scroll = INITIAL_SCROLL;
}
else if(sel > elementIndex)
{
selected = --sel;
}
}
super.getScrollBar().setRange(font.getHeight() * len);
correctScrollBarPosition(sel);
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("StringList.delete: аргумент elementIndex выходит из диапазона.");
}
}
public void deleteAll() {
synchronized(monitor)
{
Array.fill(elements, 0, count, null);
selected = 0;
scroll = INITIAL_SCROLL;
count = 0;
super.getScrollBar().setRange(0);
}
}
public void setSelectedIndex(int elementIndex) {
synchronized(monitor)
{
int lim;
if(elementIndex > (lim = count - 1)) elementIndex = lim;
if(elementIndex < 0) elementIndex = 0;
correctScrollBarPosition(selected = elementIndex);
scroll = INITIAL_SCROLL;
}
}
public void setString(int elementIndex, String text) {
int error = 0;
if(text == null) text = "";
synchronized(monitor)
{
label0:
{
if(elementIndex < 0 || elementIndex >= count)
{
error = 1;
break label0;
}
elements[elementIndex] = text;
repaint();
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("StringList.setString: аргумент elementIndex выходит из диапазона.");
}
}
public void setFont(Font font) {
if(font == null) font = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_BOLD, Font.SIZE_SMALL);
synchronized(monitor)
{
this.font = font;
super.getScrollBar().setRange(font.getHeight() * count);
correctScrollBarPosition(selected);
}
}
public int append(String text) {
int result;
if(text == null) text = "";
synchronized(monitor)
{
int len;
String[] list;
if((result = len = count) == (list = elements).length) Array.copy(list, 0, list = elements = new String[(len << 1) + 1], 0, len);
list[len++] = text;
count = len;
super.getScrollBar().setRange(font.getHeight() * len);
}
return result;
}
public int getSize() {
return count;
}
public int getSelectedIndex() {
return count <= 0 ? -1 : selected;
}
public String getSelectedString() {
int error = 0;
String result;
synchronized(monitor)
{
label0:
{
if(count <= 0)
{
error = 1;
result = null;
break label0;
}
result = elements[selected];
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("StringList.getSelectedString: список пуст.");
}
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];
}
}
if(error == 1)
{
throw new IndexOutOfBoundsException("StringList.getString: аргумент elementIndex выходит из диапазона.");
}
return result;
}
public Font getFont() {
return font;
}
protected void paint(Graphics render) {
int width = super.getWidth();
int clipLeft = render.getClipX();
int clipTop = render.getClipY();
int clipWidth = render.getClipWidth();
int clipHeight = render.getClipHeight();
synchronized(monitor)
{
int line;
int srow;
int frow;
int length = this.count;
int selected = this.selected;
String[] elements = this.elements;
Font font = this.font;
srow = clipTop / (line = font.getHeight());
frow = (clipTop + clipHeight - 1) / line;
render.setFont(font);
for(int top = srow * line, index = srow; index <= frow && index < length; top += line, index++)
{
String element;
if((element = elements[index]) == null) element = "";
if(index == selected)
{
int pos;
int wid = font.stringWidth(element);
int scroll = this.scroll;
render.setColor(RasterCanvas.getSystemColor(0x0d));
render.fillRect(0, top, width, line);
render.setColor(RasterCanvas.getSystemColor(0x0e));
render.setClip(2, top, pos = width - 4, line);
render.drawString(element, wid > pos ? scroll + 2 : 2, top, 0);
render.setClip(clipLeft, clipTop, clipWidth, clipHeight);
if((scroll -= 2) < -wid || scroll >= pos) scroll = pos - 2;
if(wid > pos) repaint();
this.scroll = scroll;
continue;
}
render.setColor(RasterCanvas.getSystemColor(0x07));
render.drawString(MultilinedStringBuilder.truncate(element, font, width - 4), 2, top, 0);
}
}
}
protected void keyboardNotify(KeyboardEvent event) {
int key = event.getKey();
DeviceSettings settings = DeviceManager.getInstance().getSettings();
switch(event.getAction())
{
case KeyboardEvent.ACTION_KEY_PRESSED:
case KeyboardEvent.ACTION_KEY_REPEATED:
if(settings.getKeyUsedAs(DeviceSettings.DEVICE_KEY_UP) == key)
{
synchronized(monitor)
{
int len;
if((len = count) > 0)
{
int sel = (selected + len - 1) % len;
correctScrollBarPosition(selected = sel);
scroll = INITIAL_SCROLL;
}
}
break;
}
if(settings.getKeyUsedAs(DeviceSettings.DEVICE_KEY_DOWN) == key)
{
synchronized(monitor)
{
int len;
if((len = count) > 0)
{
int sel = (selected + 1) % len;
correctScrollBarPosition(selected = sel);
scroll = INITIAL_SCROLL;
}
}
break;
}
break;
}
}
protected void pointerNotify(PointerEvent event) {
int action = event.getAction();
if(
event.isButtonPressed(PointerEvent.BUTTON_MAIN) || (action == PointerEvent.ACTION_BUTTON_RELEASED ||
action == PointerEvent.ACTION_POINTER_RELEASED) && event.getButton() == PointerEvent.BUTTON_MAIN
) synchronized(monitor)
{
int lim;
int line = font.getHeight();
int index = event.getY() / line;
if(index > (lim = count - 1)) index = lim;
if(index < 0) index = 0;
correctScrollBarPosition(selected = index);
if(action != PointerEvent.ACTION_BUTTON_RELEASED && action != PointerEvent.ACTION_POINTER_RELEASED) scroll = INITIAL_SCROLL;
}
}
private void correctScrollBarPosition(int selected) {
int pos;
int page;
int line = font.getHeight();
int top1 = selected * line;
int top2 = line + top1;
ScrollBar scroll = super.getScrollBar();
if(top1 < (pos = scroll.getPosition()))
{
scroll.setPosition(top1);
}
else if(top2 > pos + (page = scroll.getPage()))
{
scroll.setPosition(top2 - page);
}
else
{
repaint();
}
}
}