/*
Реализация спецификаций 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 TextField extends Item
implements Input
{
private static final class Destination extends WeakReference
implements CharDestination
{
Destination(TextField thisItem)
{
super(thisItem);
}
public void insert(char src)
{
TextField thisItem;
if((thisItem = (TextField) get()) == null)
{
return;
}
thisItem.insert(src);
}
public void insert(String src)
{
TextField thisItem;
if((thisItem = (TextField) get()) == null)
{
return;
}
thisItem.insert(src);
}
}
public static final int ANY = 0;
public static final int EMAILADDR = 1;
public static final int NUMERIC = 2;
public static final int PHONENUMBER = 3;
public static final int URL = 4;
public static final int DECIMAL = 5;
public static final int CONSTRAINT_MASK = 0xffff;
public static final int PASSWORD = 0x010000;
public static final int UNEDITABLE = 0x020000;
public static final int SENSITIVE = 0x040000;
public static final int NON_PREDICTIVE = 0x080000;
public static final int INITIAL_CAPS_WORD = 0x100000;
public static final int INITIAL_CAPS_SENTENCE = 0x200000;
private boolean controlFocused;
private boolean pointerFocused;
private int scrollPosition;
private Font font;
private TextInput input;
private CommandListener capabilities;
public TextField(String label, String text, int maxLength, int constraints)
{
this(LAYOUT_DEFAULT, -1, label, null, null, null, text, maxLength, constraints);
}
public TextField(int layout, int lockedWidth, String label,
Command[] commands, Command defaultCommand, ItemCommandListener listener,
String text, int maxLength, int constraints)
{
super(layout, lockedWidth, -1, label, Displayable.concatCommands(commands,
TextInput.getAdditionalCapabilitiesCommands(constraints, false)),
defaultCommand, listener);
TextInput input;
this.font = Font.getFont(Font.FONT_INPUT_TEXT);
this.input = input = new TextInput(text, maxLength, constraints);
this.capabilities = input.new AdditionalCapabilities(new Destination(this));
}
public void insert(String src, int position)
{
TextInput input;
synchronized(input = this.input)
{
input.insert(src, position);
if(src.length() > 0)
{
notifyPaint();
}
}
}
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)
{
notifyPaint();
}
}
}
public void delete(int offset, int length)
{
TextInput input;
synchronized(input = this.input)
{
input.delete(offset, length);
if(length > 0)
{
notifyPaint();
}
}
}
public void setString(String src)
{
TextInput input;
synchronized(input = this.input)
{
input.setString(src);
notifyPaint();
}
}
public void setChars(char[] src, int offset, int length)
{
TextInput input;
synchronized(input = this.input)
{
input.setChars(src, offset, length);
notifyPaint();
}
}
public void setConstraints(int constraints)
{
int oldConstraints;
TextInput input;
synchronized(input = this.input)
{
if((oldConstraints = input.getConstraints()) != constraints)
{
input.setConstraints(oldConstraints);
removeCommands(TextInput.getAdditionalCapabilitiesCommands(oldConstraints, false));
addCommands(TextInput.getAdditionalCapabilitiesCommands(constraints, false));
notifyPaint();
}
}
}
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);
notifyPaint();
} 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 paintContent(Graphics render, int contentWidth, int contentHeight)
{
boolean cfocused;
int a;
int s;
int x;
int scrollPosition;
char[] text;
Font font;
TextInput input;
render.setFont(font = this.font);
synchronized(input = this.input)
{
render.setColor(RasterCanvas.getSystemColor((a = (cfocused = controlFocused) ?
((input.getConstraints() & UNEDITABLE) != 0 ? 3 : 1) : 0) + 0x20));
render.drawElementOfGUI(8, a, 0, 0, 0, contentWidth, (s = font.getHeight()) + 4);
render.translate(2, 2);
render.clipRect(0, 0, contentWidth - 4, s);
render.drawChars(text = input.getChars(), 0, input.getLength(),
-(scrollPosition = this.scrollPosition) + 1, 0, Graphics.LEFT | Graphics.TOP);
if(cfocused)
{
x = font.charsWidth(text, 0, input.getCaretPosition()) - scrollPosition;
render.drawLine(x, 0, x, s - 1);
}
}
}
void onKeyPressed(int key, int charCode)
{
TextInput input;
synchronized(input = this.input)
{
input.keyPressed(key, charCode);
if(input.isChanged())
{
correctScrollPosition();
super.notifyStateChanged();
}
}
}
void onKeyRepeated(int key, int charCode)
{
TextInput input;
synchronized(input = this.input)
{
input.keyPressed(key, charCode);
if(input.isChanged())
{
correctScrollPosition();
super.notifyStateChanged();
}
}
}
void onKeyReleased(int key)
{
input.keyReleased(key);
}
void onContentPointerPressed(int x, int y, int button)
{
pointerFocused = true;
pointerHandle(scrollPosition + x - 2);
}
void onContentPointerDragged(int x, int y)
{
pointerHandle(scrollPosition + x - 2);
}
void onContentPointerReleased(int x, int y, int button)
{
pointerFocused = false;
}
void onCommandAction(Command command)
{
if(TextInput.isAdditionalCapabilitiesCommand(command))
{
capabilities.commandAction(command, getOwner());
return;
}
super.onCommandAction(command);
}
void onTraverseOut()
{
controlFocused = false;
notifyPaint();
}
boolean onTraverseNeedStayOn(int direction, int viewportWidth, int viewportHeight,
int[] visibleRectangle)
{
boolean result;
boolean cfocused;
int caretPosition;
TextInput input;
if((cfocused = controlFocused) != (controlFocused = true))
{
notifyPaint();
}
if(pointerFocused)
{
return true;
}
switch(direction)
{
case Canvas.UP:
case Canvas.DOWN:
return !cfocused;
case Canvas.LEFT:
result = false;
synchronized(input = this.input)
{
if(!cfocused)
{
input.setCaretPosition(input.getLength());
correctScrollPosition();
result = true;
}
else if((caretPosition = input.getCaretPosition()) > 0)
{
input.setCaretPosition(caretPosition - 1);
correctScrollPosition();
result = true;
}
}
return result;
case Canvas.RIGHT:
result = false;
synchronized(input = this.input)
{
if(!cfocused)
{
input.setCaretPosition(0);
correctScrollPosition();
result = true;
}
else if((caretPosition = input.getCaretPosition()) < input.getLength())
{
input.setCaretPosition(caretPosition + 1);
correctScrollPosition();
result = true;
}
}
return result;
}
return true;
}
boolean keyHandling(int key)
{
switch(key)
{
default:
return false;
case MIDletProxy.KEY_BACKSPACE:
case MIDletProxy.KEY_SHIFT:
case MIDletProxy.KEY_SPACE:
case MIDletProxy.KEY_0:
case MIDletProxy.KEY_1:
case MIDletProxy.KEY_2:
case MIDletProxy.KEY_3:
case MIDletProxy.KEY_4:
case MIDletProxy.KEY_5:
case MIDletProxy.KEY_6:
case MIDletProxy.KEY_7:
case MIDletProxy.KEY_8:
case MIDletProxy.KEY_9:
case MIDletProxy.KEY_A:
case MIDletProxy.KEY_B:
case MIDletProxy.KEY_C:
case MIDletProxy.KEY_D:
case MIDletProxy.KEY_E:
case MIDletProxy.KEY_F:
case MIDletProxy.KEY_G:
case MIDletProxy.KEY_H:
case MIDletProxy.KEY_I:
case MIDletProxy.KEY_J:
case MIDletProxy.KEY_K:
case MIDletProxy.KEY_L:
case MIDletProxy.KEY_M:
case MIDletProxy.KEY_N:
case MIDletProxy.KEY_O:
case MIDletProxy.KEY_P:
case MIDletProxy.KEY_Q:
case MIDletProxy.KEY_R:
case MIDletProxy.KEY_S:
case MIDletProxy.KEY_T:
case MIDletProxy.KEY_U:
case MIDletProxy.KEY_V:
case MIDletProxy.KEY_W:
case MIDletProxy.KEY_X:
case MIDletProxy.KEY_Y:
case MIDletProxy.KEY_Z:
case MIDletProxy.KEY_NUM_0:
case MIDletProxy.KEY_NUM_1:
case MIDletProxy.KEY_NUM_2:
case MIDletProxy.KEY_NUM_3:
case MIDletProxy.KEY_NUM_4:
case MIDletProxy.KEY_NUM_5:
case MIDletProxy.KEY_NUM_6:
case MIDletProxy.KEY_NUM_7:
case MIDletProxy.KEY_NUM_8:
case MIDletProxy.KEY_NUM_9:
case MIDletProxy.KEY_NUM_STAR:
case MIDletProxy.KEY_NUM_PLUS:
case MIDletProxy.KEY_NUM_SEPARATOR:
case MIDletProxy.KEY_NUM_MINUS:
case MIDletProxy.KEY_NUM_DECIMAL:
case MIDletProxy.KEY_NUM_DIVIDE:
case MIDletProxy.KEY_LSHIFT:
case MIDletProxy.KEY_RSHIFT:
case MIDletProxy.KEY_SEMICOLON:
case MIDletProxy.KEY_EQUAL:
case MIDletProxy.KEY_COMMA:
case MIDletProxy.KEY_MINUS:
case MIDletProxy.KEY_PERIOD:
case MIDletProxy.KEY_SLASH:
case MIDletProxy.KEY_GRAVE:
case MIDletProxy.KEY_LBRACKET:
case MIDletProxy.KEY_BACKSLASH:
case MIDletProxy.KEY_RBRACKET:
case MIDletProxy.KEY_APOSTROPHE:
return true;
}
}
int getPreferredContentWidth(int contentHeight, int containerClientWidth)
{
return 0x80;
}
int getPreferredContentHeight(int contentWidth)
{
return font.getHeight() + 4;
}
private void pointerHandle(int x)
{
int i;
int w1;
int w2;
int length;
int caretPosition;
char[] text;
Font font;
TextInput input;
synchronized(input = this.input)
{
font = this.font;
text = input.getChars();
length = input.getLength();
label0:
{
for(w1 = 0, i = 1; i <= length; w1 = w2, i++)
{
w2 = font.charsWidth(text, 0, i);
if(x >= w1 && x < w2)
{
caretPosition = x - w1 <= w2 - x ? i - 1 : i;
break label0;
}
}
caretPosition = length;
}
input.setCaretPosition(caretPosition);
correctScrollPosition();
}
}
private void insert(char src)
{
TextInput input;
synchronized(input = this.input)
{
input.insert(src);
if(input.isChanged())
{
correctScrollPosition();
super.notifyStateChanged();
}
}
}
private void insert(String src)
{
TextInput input;
synchronized(input = this.input)
{
input.insert(src);
if(input.isChanged())
{
correctScrollPosition();
super.notifyStateChanged();
}
}
}
private void correctScrollPosition()
{
int size;
int charsWidth;
int scrollPosition;
TextInput input;
if((charsWidth = font.charsWidth((input = this.input).getChars(),
0, input.getCaretPosition())) < (scrollPosition = this.scrollPosition) +
(size = super.getPreferredWidth()) / 4 ||
charsWidth > scrollPosition + 3 * size / 4)
{
this.scrollPosition = Math.max(charsWidth - size / 2, 0);
}
notifyPaint();
}
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]));
}
}