/*
Реализация спецификаций 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.media.graphics.*;
import malik.emulator.microedition.lcdui.*;
import malik.emulator.util.*;
public class StringItem extends AppearanceModeItem
{
private static final String NEW_LINE = "\n";
private static void writeText(StringBuilder builder, String text) {
builder.clear();
builder.append(text);
if(text != null)
{
if(text.startsWith(NEW_LINE)) builder.delete(0);
if(text.endsWith(NEW_LINE) && !builder.isEmpty()) builder.delete(builder.length() - 1);
}
}
private char[] buffer;
private Font textFont;
private String textAsString;
private final MultilinedStringBuilder textAsBuilder;
public StringItem(String label, String text) {
this(label, text, PLAIN);
}
public StringItem(String label, String text, int appearanceMode) {
super(label, appearanceMode);
MultilinedStringBuilder builder;
this.textFont = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_MEDIUM);
this.textAsString = text;
this.textAsBuilder = builder = new FastMultilinedStringBuilder();
writeText(builder, text);
}
public void setText(String text) {
StringBuilder builder;
synchronized(builder = textAsBuilder)
{
writeText(builder, textAsString = text);
}
requestInvalidate();
}
public void setFont(Font font) {
textFont = font == null ? Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_MEDIUM) : font;
requestInvalidate();
}
public String getText() {
return textAsString;
}
public Font getFont() {
return textFont;
}
void paint(Graphics render, int contentWidth, int contentHeight) {
boolean f;
boolean p;
boolean c;
int l;
int t;
int w;
Font font;
MultilinedStringBuilder builder;
switch(appearanceMode)
{
default:
c = false;
l = t = 0;
w = contentWidth;
render.setColor(RasterCanvas.getSystemColor(0x28));
break;
case HYPERLINK:
c = false;
l = t = (p = pressed) ? 1 : 0;
w = contentWidth > 1 ? contentWidth - 1 : 0;
render.setColor(RasterCanvas.getSystemColor(focused ? p ? 0x25 : 0x27 : 0x24));
break;
case BUTTON:
c = true;
f = focused;
l = ((p = pressed) ? 1 : 0) + (contentWidth >> 1);
t = p ? 5 : 4;
w = contentWidth > 8 ? contentWidth - 8 : 0;
render.drawElement(4, f ? p ? 1 : 3 : 0, 0, 0, 0, contentWidth, contentHeight);
render.setColor(RasterCanvas.getSystemColor(f ? p ? 0x25 : 0x27 : 0x24));
break;
}
render.setFont(font = textFont);
synchronized(builder = textAsBuilder)
{
int line;
int srow;
int frow;
int clipTop;
char[] lbuf = buffer;
srow = (clipTop = render.getClipY() - t) / (line = font.getHeight());
frow = (clipTop + render.getClipHeight() - 1) / line;
builder.split(font, w);
for(int len = builder.lines(), top = t + srow * line, index = srow < 0 ? 0 : srow; index <= frow && index < len; top += line, index++)
{
int lofs = builder.lineOffset(index);
int llen = builder.lineLength(index);
if(lbuf == null || lbuf.length < llen) lbuf = buffer = new char[StringBuilder.optimalCapacity(llen)];
builder.copy(lofs, lofs + llen, lbuf, 0);
render.drawChars(lbuf, 0, llen, l, top, c ? Graphics.HCENTER | Graphics.TOP : Graphics.LEFT | Graphics.TOP);
}
}
}
boolean onFocusMove(int direction, int viewportWidth, int viewportHeight, int[] visibleRectangle) {
int max;
int pos1;
int pos2;
int size;
int delta;
if(!super.onFocusMove(direction, viewportWidth, viewportHeight, visibleRectangle))
{
pressed = false;
return true;
}
switch(direction)
{
default:
break;
case DIR_LEFT:
if((pos1 = visibleRectangle[LEFT]) <= 0) return false;
visibleRectangle[LEFT] = pos1 > (delta = viewportWidth >> 1) ? pos1 - delta : 0;
break;
case DIR_RIGHT:
if((pos2 = (pos1 = visibleRectangle[LEFT]) + (size = visibleRectangle[WIDTH])) >= (max = contentWidth)) return false;
visibleRectangle[LEFT] = pos2 < max - (delta = viewportWidth >> 1) ? pos1 + delta : max - size;
break;
case DIR_UP:
if((pos1 = visibleRectangle[TOP]) <= 0) return false;
visibleRectangle[TOP] = pos1 > (delta = textFont.getHeight()) ? pos1 - delta : 0;
break;
case DIR_DOWN:
if((pos2 = (pos1 = visibleRectangle[TOP]) + (size = visibleRectangle[HEIGHT])) >= (max = contentHeight)) return false;
visibleRectangle[TOP] = pos2 < max - (delta = textFont.getHeight()) ? pos1 + delta : max - size;
break;
}
return true;
}
boolean hasRowBreakBefore(int layout, int alignment) {
String text;
return super.hasRowBreakBefore(layout, alignment) || (text = textAsString) != null && text.startsWith("\n");
}
boolean hasRowBreakAfter(int layout, int alignment) {
String text;
return super.hasRowBreakAfter(layout, alignment) || (text = textAsString) != null && text.endsWith("\n");
}
int getDefaultLayout() {
return appearanceMode == PLAIN ? LAYOUT_EXPAND : LAYOUT_DEFAULT;
}
int getMinimumContentWidth() {
int result = 0;
StringBuilder builder;
synchronized(builder = textAsBuilder)
{
if(!builder.isEmpty()) result = 100;
}
return result + sizeAppendix();
}
int getMinimumContentHeight() {
int result = 0;
MultilinedStringBuilder builder;
synchronized(builder = textAsBuilder)
{
if(!builder.isEmpty())
{
Font font;
builder.split(font = textFont, Integer.MAX_VALUE);
result = font.getHeight() * builder.lines();
}
}
return result + sizeAppendix();
}
int getPreferredContentWidth(int contentHeight) {
int result = 0;
int maxWidth = contentHeight >= 0 ? width : 100;
MultilinedStringBuilder builder;
synchronized(builder = textAsBuilder)
{
if(!builder.isEmpty())
{
int index;
Font font;
builder.split(font = textFont, maxWidth);
index = builder.lines();
for(char[] buf = buffer; index-- > 0; )
{
int lwid;
int lofs = builder.lineOffset(index);
int llen = builder.lineLength(index);
if(buf == null || buf.length < llen) buf = buffer = new char[StringBuilder.optimalCapacity(llen)];
builder.copy(lofs, lofs + llen, buf, 0);
if(result < (lwid = font.charsWidth(buf, 0, llen))) result = lwid;
}
}
}
return result + sizeAppendix();
}
int getPreferredContentHeight(int contentWidth) {
int result = 0;
int sapp = sizeAppendix();
MultilinedStringBuilder builder;
synchronized(builder = textAsBuilder)
{
if(!builder.isEmpty())
{
Font font;
builder.split(font = textFont, contentWidth >= sapp ? contentWidth - sapp : Integer.MAX_VALUE);
result = font.getHeight() * builder.lines();
}
}
return result + sapp;
}
private int sizeAppendix() {
switch(appearanceMode)
{
default:
return 0;
case HYPERLINK:
return 1;
case BUTTON:
return 8;
}
}
}