/*
Реализация спецификаций 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.io.j2me.input.*;
import malik.emulator.media.graphics.*;
public class TextBox extends ScrollingScreen
implements Input
{
private static final class Destination extends WeakReference
implements CharDestination
{
Destination(TextBox thisScreen)
{
super(thisScreen);
}
public void insert(char src)
{
TextBox thisScreen;
if((thisScreen = (TextBox) get()) == null)
{
return;
}
thisScreen.insert(src);
}
public void insert(String src)
{
TextBox thisScreen;
if((thisScreen = (TextBox) get()) == null)
{
return;
}
thisScreen.insert(src);
}
}
private Font font;
private TextInput input;
private ScrollBarStyle systemStyle;
private CommandListener capabilities;
public TextBox(String title, String text, int maxLength, int constraints)
{
this(false, false, title, null, null, null, null, text, maxLength, constraints);
}
public TextBox(boolean fullScreenMode, String title, Ticker ticker,
Command[] commands, Command defaultCommand, CommandListener listener,
String text, int maxLength, int constraints)
{
this(true, fullScreenMode, title, ticker, commands, defaultCommand, listener, text, maxLength, constraints);
}
private TextBox(boolean system, boolean fullScreenMode, String title, Ticker ticker,
Command[] commands, Command defaultCommand, CommandListener listener,
String text, int maxLength, int constraints)
{
super(system, fullScreenMode, title, ticker, concatCommands(commands,
TextInput.getAdditionalCapabilitiesCommands(constraints, true)),
defaultCommand, listener, VERTICAL);
int charArrayLength = TextInput.DEFAULT_CHAR_ARRAY_LENGTH << 4;
Font font;
TextInput input;
this.font = font = Font.getFont(Font.FONT_INPUT_TEXT);
this.input = input = new TextInput(text, maxLength, constraints, charArrayLength);
this.systemStyle = new ScrollBarSystem(font.getHeight());
this.capabilities = input.new AdditionalCapabilities(new Destination(this));
updateView();
}
public void insert(String src, int position)
{
TextInput input;
synchronized(input = this.input)
{
input.insert(src, position);
if(src.length() > 0)
{
updateView();
}
}
}
public void insert(char[] src, int offset, int length, int position)
{
TextInput input;
synchronized(input = this.input)
{
input.insert(src, offset, length, position);
if(length > 0)
{
updateView();
}
}
}
public void delete(int offset, int length)
{
TextInput input;
synchronized(input = this.input)
{
input.delete(offset, length);
if(length > 0)
{
updateView();
}
}
}
public void setString(String src)
{
TextInput input;
synchronized(input = this.input)
{
input.setString(src);
updateView();
}
}
public void setChars(char[] src, int offset, int length)
{
TextInput input;
synchronized(input = this.input)
{
input.setChars(src, offset, length);
updateView();
}
}
public void setConstraints(int constraints)
{
int oldConstraints;
TextInput input;
synchronized(input = this.input)
{
if((oldConstraints = input.getConstraints()) != constraints)
{
input.setConstraints(constraints);
removeCommands(TextInput.getAdditionalCapabilitiesCommands(oldConstraints, true));
addCommands(TextInput.getAdditionalCapabilitiesCommands(constraints, true));
updateView();
}
}
}
public void setInitialInputMode(String characterSubset)
{
input.setInitialInputMode(characterSubset);
}
public int setMaxSize(int maxLength)
{
int result;
TextInput input;
synchronized(input = this.input)
{
if(input.getMaxSize() != maxLength)
{
result = input.setMaxSize(maxLength);
updateView();
} else
{
result = maxLength;
}
}
return result;
}
public int size()
{
return input.size();
}
public int getChars(char[] dst)
{
int result;
TextInput input;
synchronized(input = this.input)
{
result = input.getChars(dst);
}
return result;
}
public int getConstraints()
{
return input.getConstraints();
}
public int getCaretPosition()
{
return input.getCaretPosition();
}
public int getMaxSize()
{
return input.getMaxSize();
}
public String getString()
{
String result;
TextInput input;
synchronized(input = this.input)
{
result = input.getString();
}
return result;
}
void paint(Graphics render, ScrollBar horzScrollBar, ScrollBar vertScrollBar)
{
int i;
int s;
int len;
int top;
int bottom;
int lineHeight;
int topMarginElement;
int caretLine;
int caretPosition;
char[] text;
Font font;
TextInput input;
bottom = (top = vertScrollBar.getPosition()) + vertScrollBar.getPage();
lineHeight = (font = this.font).getHeight();
topMarginElement = 0;
render.setFont(font);
synchronized(input = this.input)
{
render.setColor(RasterCanvas.getSystemColor(
(input.getConstraints() & UNEDITABLE) != 0 ? 0x23 : 0x21));
caretLine = input.getLineAt(caretPosition = input.getCaretPosition());
caretPosition -= input.getLineStart(caretLine);
text = input.getChars();
for(len = input.getLinesCount(), i = 0; i < len; render.translate(0, lineHeight),
topMarginElement += lineHeight, i++)
{
if(topMarginElement >= bottom || topMarginElement + lineHeight <= top)
{
continue;
}
render.drawChars(text, s = input.getLineStart(i), input.getLineLength(i),
1, 0, Graphics.LEFT | Graphics.TOP);
if(i != caretLine)
{
continue;
}
s = font.charsWidth(text, s, caretPosition);
render.drawLine(s, 0, s, lineHeight - 1);
}
}
}
void paintClient(Graphics render, int width, int height, int clipLeft, int clipTop, int clipWidth, int clipHeight)
{
Graphics clientRender;
render.drawElementOfGUI(8, (input.getConstraints() & UNEDITABLE) != 0 ? 3 : 1, 0,
0, 0, render.getClipWidth(), render.getClipHeight());
(clientRender = getClientContext()).reset();
clientRender.translate(getClientLeft(), getClientTop());
clientRender.setClip(0, 0, getClientWidth(), getClientHeight());
paint(clientRender);
}
void paintVertScrollBar(Graphics clientRender, ScrollBar scrollbar, int length, int width)
{
systemStyle.paintVertScrollBar(clientRender, scrollbar, length, width);
}
void onKeyPressed(int key, int charCode)
{
TextInput input;
switch(key)
{
default:
if(charCode <= 0)
{
break;
}
/* fall through */
case MIDletProxy.KEY_TAB:
case MIDletProxy.KEY_SHIFT:
case MIDletProxy.KEY_LSHIFT:
case MIDletProxy.KEY_RSHIFT:
case MIDletProxy.KEY_BACKSPACE:
case MIDletProxy.KEY_ENTER:
synchronized(input = this.input)
{
input.keyPressed(key, charCode);
if(input.isChanged())
{
updateView();
correctScrollBarPositionToLine();
}
}
return;
case MIDletProxy.KEY_LEFT:
synchronized(input = this.input)
{
input.setCaretPosition(input.getCaretPosition() - 1);
correctScrollBarPositionToLine();
}
return;
case MIDletProxy.KEY_RIGHT:
synchronized(input = this.input)
{
input.setCaretPosition(input.getCaretPosition() + 1);
correctScrollBarPositionToLine();
}
return;
case MIDletProxy.KEY_UP:
synchronized(input = this.input)
{
moveCaretUp();
correctScrollBarPositionToLine();
}
return;
case MIDletProxy.KEY_DOWN:
synchronized(input = this.input)
{
moveCaretDown();
correctScrollBarPositionToLine();
}
return;
}
super.onKeyPressed(key, charCode);
}
void onKeyRepeated(int key, int charCode)
{
TextInput input;
switch(key)
{
default:
if(charCode <= 0)
{
break;
}
/* fall through */
case MIDletProxy.KEY_TAB:
case MIDletProxy.KEY_SHIFT:
case MIDletProxy.KEY_LSHIFT:
case MIDletProxy.KEY_RSHIFT:
case MIDletProxy.KEY_BACKSPACE:
case MIDletProxy.KEY_ENTER:
synchronized(input = this.input)
{
input.keyPressed(key, charCode);
if(input.isChanged())
{
updateView();
correctScrollBarPositionToLine();
}
}
return;
case MIDletProxy.KEY_LEFT:
synchronized(input = this.input)
{
input.setCaretPosition(input.getCaretPosition() - 1);
}
correctScrollBarPositionToLine();
return;
case MIDletProxy.KEY_RIGHT:
synchronized(input = this.input)
{
input.setCaretPosition(input.getCaretPosition() + 1);
}
correctScrollBarPositionToLine();
return;
case MIDletProxy.KEY_UP:
synchronized(this.input)
{
moveCaretUp();
correctScrollBarPositionToLine();
}
return;
case MIDletProxy.KEY_DOWN:
synchronized(this.input)
{
moveCaretDown();
correctScrollBarPositionToLine();
}
return;
}
super.onKeyRepeated(key, charCode);
}
void onKeyReleased(int key)
{
switch(key)
{
case MIDletProxy.KEY_SHIFT:
case MIDletProxy.KEY_LSHIFT:
case MIDletProxy.KEY_RSHIFT:
input.keyReleased(key);
return;
}
super.onKeyReleased(key);
}
void onClientPointerPressed(int x, int y, int button)
{
pointerHandle(x, y);
}
void onClientPointerDragged(int x, int y)
{
pointerHandle(x, y);
}
void onClientPointerReleased(int x, int y, int button)
{
pointerHandle(x, y);
}
void onCommandAction(Command command)
{
if(TextInput.isAdditionalCapabilitiesCommand(command))
{
capabilities.commandAction(command, this);
return;
}
super.onCommandAction(command);
}
void onVertScrollBarPointerPressed(ScrollBar scrollbar, int length, int width,
int x, int y, int button)
{
systemStyle.onVertScrollBarPointerPressed(scrollbar, length, width, x, y, button);
}
void onVertScrollBarPointerDragged(ScrollBar scrollbar, int length, int width,
int x, int y)
{
systemStyle.onVertScrollBarPointerDragged(scrollbar, length, width, x, y);
}
void onVertScrollBarPointerReleased(ScrollBar scrollbar, int length, int width,
int x, int y, int button)
{
systemStyle.onVertScrollBarPointerReleased(scrollbar, length, width, x, y, button);
}
int getMarginLeft()
{
return 2;
}
int getMarginTop()
{
return 2;
}
int getMarginRight()
{
return getVertScrollBar().isVisible() ? getVertScrollBarWidth() + 2 : 2;
}
int getMarginBottom()
{
return getHorzScrollBar().isVisible() ? getHorzScrollBarWidth() + 2 : 2;
}
int getVertScrollBarWidth()
{
return systemStyle.getVertScrollBarWidth();
}
private void pointerHandle(int x, int y)
{
int i;
int w1;
int w2;
int start;
int length;
int caretLine;
int caretPosition;
char[] text;
Font font;
TextInput input;
synchronized(input = this.input)
{
font = this.font;
text = input.getChars();
caretLine = Math.min(y / font.getHeight(), input.getLinesCount() - 1);
start = input.getLineStart(caretLine);
length = input.getLineLength(caretLine);
label0:
{
for(w1 = 0, i = 1; i <= length; w1 = w2, i++)
{
w2 = font.charsWidth(text, start, i);
if(x >= w1 && x < w2)
{
caretPosition = x - w1 <= w2 - x ? i - 1 : i;
break label0;
}
}
caretPosition = length;
}
input.setCaretPosition(start + caretPosition);
correctScrollBarPositionToLine();
}
}
private void insert(char src)
{
TextInput input;
synchronized(input = this.input)
{
input.insert(src);
if(input.isChanged())
{
updateView();
correctScrollBarPositionToLine();
}
}
}
private void insert(String src)
{
TextInput input;
synchronized(input = this.input)
{
input.insert(src);
if(input.isChanged())
{
updateView();
correctScrollBarPositionToLine();
}
}
}
private void updateView()
{
Font font;
TextInput input;
(input = this.input).split(font = this.font, getClientWidth() - 2);
getVertScrollBar().setRange(input.getLinesCount() * font.getHeight());
callSeriallyPaintScreen(CLIENT);
}
private void moveCaretUp()
{
int i;
int w1;
int w2;
int start;
int length;
int charsWidth;
int caretLine;
int caretPosition;
char[] text;
Font font;
TextInput input;
if((caretLine = (input = this.input).
getLineAt(caretPosition = input.getCaretPosition())) <= 0)
{
return;
}
font = this.font;
caretPosition -= (start = input.getLineStart(caretLine));
charsWidth = font.charsWidth(text = input.getChars(), start, caretPosition);
start = input.getLineStart(--caretLine);
length = input.getLineLength(caretLine);
label0:
{
for(w1 = 0, i = 1; i <= length; w1 = w2, i++)
{
w2 = font.charsWidth(text, start, i);
if(charsWidth >= w1 && charsWidth < w2)
{
caretPosition = charsWidth - w1 <= w2 - charsWidth ? i - 1 : i;
break label0;
}
}
caretPosition = length;
}
input.setCaretPosition(start + caretPosition);
}
private void moveCaretDown()
{
int i;
int w1;
int w2;
int start;
int length;
int charsWidth;
int caretLine;
int caretPosition;
char[] text;
Font font;
TextInput input;
if((caretLine = (input = this.input).
getLineAt(caretPosition = input.getCaretPosition())) >= input.getLinesCount() - 1)
{
return;
}
font = this.font;
caretPosition -= (start = input.getLineStart(caretLine));
charsWidth = font.charsWidth(text = input.getChars(), start, caretPosition);
start = input.getLineStart(++caretLine);
length = input.getLineLength(caretLine);
label0:
{
for(w1 = 0, i = 1; i <= length; w1 = w2, i++)
{
w2 = font.charsWidth(text, start, i);
if(charsWidth >= w1 && charsWidth < w2)
{
caretPosition = charsWidth - w1 <= w2 - charsWidth ? i - 1 : i;
break label0;
}
}
caretPosition = length;
}
input.setCaretPosition(start + caretPosition);
}
private void correctScrollBarPositionToLine()
{
int pos;
int need;
int lineHeight = font.getHeight();
ScrollBar scrollbar = getVertScrollBar();
if((pos = scrollbar.getPosition()) > (need = input.getCaretLine() * lineHeight))
{
scrollbar.setPosition(need);
}
else if(pos < (need -= scrollbar.getPage() - lineHeight))
{
scrollbar.setPosition(need);
}
callSeriallyPaintScreen(CLIENT);
}
private void addCommands(Command[] commands)
{
int i;
int len;
for(len = commands.length, i = 0; i < len; super.addCommand(commands[i]), i++);
}
private void removeCommands(Command[] commands)
{
int i;
for(i = commands.length; i-- > 0; super.removeCommand(commands[i]));
}
}