/*
Реализация спецификаций 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.application.*;
import malik.emulator.media.graphics.*;
import malik.emulator.util.*;
public class Gauge extends InteractiveItem
{
public static final int INDEFINITE = -1;
public static final int CONTINUOUS_IDLE = 0;
public static final int INCREMENTAL_IDLE = 1;
public static final int CONTINUOUS_RUNNING = 2;
public static final int INCREMENTAL_UPDATING = 3;
private static final int THUMB_HEIGHT;
private static final int TRACK_HEIGHT;
private static final int THUMB_WIDTH;
private static final Font FONT;
static {
int i;
int s = RasterCanvas.getGUIElementSize(11, 0, 0);
THUMB_WIDTH = (i = (short) s) == -1 ? 8 : i;
THUMB_HEIGHT = (i = s >> 16) == -1 ? 16 : i;
TRACK_HEIGHT = (i = RasterCanvas.getGUIElementSize(11, 3, 0) >> 16) == -1 ? 8 : i;
FONT = Font.getFont(Font.FACE_SYSTEM, Font.STYLE_PLAIN, Font.SIZE_SMALL);
}
final boolean interactive;
private boolean newInput;
private boolean pressed;
private int frame;
private int width;
private int height;
private long value;
private final char[] buffer;
private final StringBuilder text;
private final Object monitor;
public Gauge(String label, boolean interactive, int maximumValue, int initialValue) {
super(label);
if(interactive ? maximumValue <= 0 : maximumValue != INDEFINITE && maximumValue <= 0)
{
throw new IllegalArgumentException("Gauge: аргумент maximumValue имеет недопустимое значение.");
}
if(!interactive && maximumValue == INDEFINITE && (initialValue < CONTINUOUS_IDLE || initialValue > INCREMENTAL_UPDATING))
{
throw new IllegalArgumentException("Gauge: аргумент initialValue имеет недопустимое значение.");
}
if(maximumValue > 0)
{
if(initialValue < 0) initialValue = 0;
if(initialValue > maximumValue) initialValue = maximumValue;
}
this.interactive = interactive;
this.newInput = true;
this.buffer = interactive ? new char[23] : null;
this.text = interactive ? new StringBuilder(23) : null;
this.monitor = new Object();
setValue(initialValue, maximumValue);
}
public void setValue(int currentValue) {
int error = 0;
synchronized(monitor)
{
label0:
{
int maximumValue;
if((maximumValue = (int) (value >> 32)) == INDEFINITE && (currentValue < CONTINUOUS_IDLE || currentValue > INCREMENTAL_UPDATING))
{
error = 1;
break label0;
}
if(maximumValue > 0)
{
if(currentValue < 0) currentValue = 0;
if(currentValue > maximumValue) currentValue = maximumValue;
}
else if(currentValue == INCREMENTAL_UPDATING)
{
frame++;
}
newInput = true;
setValue(currentValue, maximumValue);
}
}
if(error == 1)
{
throw new IllegalArgumentException("Gauge.setValue: аргумент currentValue имеет недопустимое значение.");
}
requestPaint();
}
public void setMaxValue(int maximumValue) {
if(interactive ? maximumValue <= 0 : maximumValue != INDEFINITE && maximumValue <= 0)
{
throw new IllegalArgumentException("Gauge.setMaxValue: аргумент maximumValue имеет недопустимое значение.");
}
synchronized(monitor)
{
int maximumPrevious;
int currentValue;
long fields;
currentValue = (int) (fields = value);
maximumPrevious = (int) (fields >> 32);
if(maximumValue > 0)
{
if(maximumPrevious == INDEFINITE)
{
currentValue = 0;
}
else if(currentValue > maximumValue)
{
currentValue = maximumValue;
}
}
else if(maximumPrevious > 0)
{
currentValue = CONTINUOUS_IDLE;
}
newInput = true;
setValue(currentValue, maximumValue);
}
requestPaint();
}
public boolean isInteractive() {
return interactive;
}
public int getValue() {
return (int) value;
}
public int getMaxValue() {
return (int) (value >> 32);
}
strictfp void paint(Graphics render, int contentWidth, int contentHeight) {
int nframe;
int current;
int maximum;
Object monitor;
synchronized(monitor = this.monitor)
{
long fields;
current = (int) (fields = value);
maximum = (int) (fields >> 32);
}
if(interactive)
{
int left;
int top;
int len;
char[] buf = buffer;
StringBuilder builder = text;
width = contentWidth;
height = contentHeight;
top = TRACK_HEIGHT < THUMB_HEIGHT ? (THUMB_HEIGHT - TRACK_HEIGHT) >> 1 : 0;
render.drawElement(11, 3, focused ? 1 : 0, 1, top, contentWidth - 2, TRACK_HEIGHT);
left = (int) ((long) (contentWidth - THUMB_WIDTH) * (long) current / (long) maximum);
top = THUMB_HEIGHT < TRACK_HEIGHT ? (TRACK_HEIGHT - THUMB_HEIGHT) >> 1 : 0;
render.drawElement(11, 0, focused ? pressed ? 1 : 3 : 0, left, top, THUMB_WIDTH, THUMB_HEIGHT);
if((top = TRACK_HEIGHT < THUMB_HEIGHT ? THUMB_HEIGHT : TRACK_HEIGHT) < contentHeight)
{
builder.clear();
builder.append(current).append(" / ").append(maximum).copy(0, len = builder.length(), buf, 0);
render.setFont(FONT);
render.setColor(RasterCanvas.getSystemColor(0x28));
render.drawChars(buf, 0, len, contentWidth, top, Graphics.RIGHT | Graphics.TOP);
}
return;
}
if(maximum > 0)
{
int width = (int) ((long) (contentWidth - 4) * (long) current / (long) maximum);
render.drawElement(9, 0, 0, 0, 0, contentWidth, contentHeight);
if(width > 0) render.drawElement(9, 1, 0, 2, 2, width, contentHeight - 4);
return;
}
switch(current)
{
default:
render.drawElement(9, 0, 0, 0, 0, contentWidth, contentHeight);
return;
case CONTINUOUS_RUNNING:
synchronized(monitor)
{
nframe = frame++;
}
requestPaint();
break;
case INCREMENTAL_UPDATING:
nframe = frame;
break;
}
render.drawElement(9, 0, 0, 0, 0, contentWidth, contentHeight);
{
int width = (int) (0.236067977f * (float) (contentWidth - 4));
int half = (contentWidth - width - 4) >> 1;
int left = (int) (Math.sin(0.196349540849362077d * (double) nframe) * (double) half) + half;
render.drawElement(9, 1, 0, left + 2, 2, width, contentHeight - 4);
}
}
void onKeyboardEvent(KeyboardEvent event) {
int digit;
if(interactive && (digit = event.getCharCode() - '0') >= 0 && digit <= 9)
{
int oldcurr;
long newcurr;
synchronized(monitor)
{
int maximum;
long fields;
oldcurr = (int) (fields = value);
maximum = (int) (fields >> 32);
if(newInput = (newcurr = newInput ? (long) digit : 10L * (long) oldcurr + (long) digit) < 0L || newcurr > (long) maximum) newcurr = (long) maximum;
setValue((int) newcurr, maximum);
}
if((long) oldcurr != newcurr)
{
super.notifyStateChanged();
super.requestPaint();
}
}
}
void onPointerEvent(PointerEvent event) {
if(interactive)
{
int x = event.getX();
int y = event.getY();
switch(event.getAction())
{
case PointerEvent.ACTION_BUTTON_PRESSED:
case PointerEvent.ACTION_POINTER_PRESSED:
if(event.getButton() == PointerEvent.BUTTON_MAIN && y >= 0 && y < (THUMB_HEIGHT < TRACK_HEIGHT ? TRACK_HEIGHT : THUMB_HEIGHT))
{
int oldcurr;
int newcurr;
synchronized(monitor)
{
int left;
int maximum;
long fields;
oldcurr = (int) (fields = value);
maximum = (int) (fields >> 32);
left = (int) ((long) (width - THUMB_WIDTH) * (long) oldcurr / (long) maximum);
if(x >= left + THUMB_WIDTH)
{
if((newcurr = oldcurr + (maximum >= 32 ? maximum / 16 : 1)) < 0 || newcurr > maximum) newcurr = maximum;
newInput = true;
}
else if(x < left)
{
if((newcurr = oldcurr - (maximum >= 32 ? maximum / 16 : 1)) < 0) newcurr = 0;
newInput = true;
}
else
{
newcurr = oldcurr;
pressed = true;
}
setValue(newcurr, maximum);
}
if(oldcurr != newcurr) super.notifyStateChanged();
requestPaint();
}
break;
case PointerEvent.ACTION_POINTER_DRAGGED:
if(pressed)
{
computeValue(x);
requestPaint();
}
break;
case PointerEvent.ACTION_POINTER_RELEASED:
case PointerEvent.ACTION_BUTTON_RELEASED:
if(pressed)
{
pressed = false;
computeValue(x);
requestPaint();
}
break;
}
}
}
void onFocusLost() {
pressed = false;
super.onFocusLost();
}
boolean onFocusMove(int direction, int viewportWidth, int viewportHeight, int[] visibleRectangle) {
int w;
int h;
int oldcurr;
int newcurr;
if(!interactive) return false;
visibleRectangle[0] = viewportWidth >= (w = width) ? 0 : w - viewportWidth;
visibleRectangle[1] = viewportHeight >= (h = height) ? 0 : h - viewportHeight;
visibleRectangle[2] = viewportWidth >= w ? w : viewportWidth;
visibleRectangle[3] = viewportHeight >= h ? h : viewportHeight;
if(!super.onFocusMove(direction, viewportWidth, viewportHeight, visibleRectangle))
{
pressed = false;
return true;
}
switch(direction)
{
default:
return false;
case DIR_LEFT:
synchronized(monitor)
{
int maximum;
long fields;
oldcurr = (int) (fields = value);
maximum = (int) (fields >> 32);
if((newcurr = oldcurr - 1) < 0) newcurr = 0;
newInput = true;
setValue(newcurr, maximum);
}
break;
case DIR_RIGHT:
synchronized(monitor)
{
int maximum;
long fields;
oldcurr = (int) (fields = value);
maximum = (int) (fields >> 32);
if((newcurr = oldcurr + 1) > maximum) newcurr = maximum;
newInput = true;
setValue(newcurr, maximum);
}
break;
}
if(oldcurr != newcurr)
{
super.notifyStateChanged();
super.requestPaint();
}
return true;
}
boolean hasRowBreakBefore(int layout, int alignment) {
return interactive || super.hasRowBreakBefore(layout, alignment);
}
boolean hasRowBreakAfter(int layout, int alignment) {
return interactive || super.hasRowBreakAfter(layout, alignment);
}
int getMinimumContentWidth() {
return 100;
}
int getMinimumContentHeight() {
return interactive ? (TRACK_HEIGHT < THUMB_HEIGHT ? THUMB_HEIGHT : TRACK_HEIGHT) + FONT.getHeight() : 24;
}
private void setValue(int currentValue, int maximumValue) {
this.value = (long) maximumValue << 32 | (long) currentValue;
}
private strictfp void computeValue(int x) {
int oldcurr;
int newcurr;
synchronized(monitor)
{
int contentWidth;
int maximum;
long fields;
double position;
oldcurr = (int) (fields = value);
maximum = (int) (fields >> 32);
if((contentWidth = width - THUMB_WIDTH) <= 0) contentWidth = 1;
position = (double) (x - (THUMB_WIDTH >> 1)) * (double) maximum / (double) contentWidth;
newcurr = 0.d > position ? 0 : position > (double) maximum ? maximum : (int) position;
newInput = true;
setValue(newcurr, maximum);
}
if(oldcurr != newcurr) super.notifyStateChanged();
}
}