This commit is contained in:
@@ -20,6 +20,7 @@ public class StatusBar extends JPanel {
|
||||
private final JLabel luName;
|
||||
private final JLabel lockStatus;
|
||||
private final JLabel modelInfo;
|
||||
private final JButton lpButton;
|
||||
|
||||
private Telnet3270Client client;
|
||||
private TerminalPanel terminalPanel;
|
||||
@@ -45,7 +46,7 @@ public class StatusBar extends JPanel {
|
||||
modelInfo = createLabel("", oiaFont, OIA_DIM);
|
||||
cursorPosition = createLabel("001/001", oiaFont, OIA_FG);
|
||||
|
||||
JButton lpButton = new JButton("LightPen: OFF");
|
||||
lpButton = new JButton("LightPen: OFF");
|
||||
lpButton.setFont(oiaFont);
|
||||
lpButton.setForeground(OIA_FG);
|
||||
lpButton.setBackground(OIA_BG);
|
||||
@@ -177,5 +178,11 @@ public class StatusBar extends JPanel {
|
||||
int row = sb.getCursorRow() + 1;
|
||||
int col = sb.getCursorCol() + 1;
|
||||
cursorPosition.setText(String.format("%03d/%03d", row, col));
|
||||
|
||||
// Light Pen indicator — sync with actual state
|
||||
if (terminalPanel != null) {
|
||||
lpButton.setText("LightPen: " + (terminalPanel.isLightPenMode() ? "ON" : "OFF"));
|
||||
lpButton.setForeground(terminalPanel.isLightPenMode() ? new Color(255, 255, 80) : OIA_FG);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,7 +215,12 @@ public class TerminalPanel extends JPanel {
|
||||
sb.setCursorAddress(newAddr);
|
||||
clearSelection();
|
||||
if (lightPenMode) {
|
||||
if (client.getInputProcessor().lightPenSelect(newAddr)) {
|
||||
System.out.println("LP click: row=" + selectionStartRow + " col=" + selectionStartCol
|
||||
+ " addr=" + newAddr + " mouseY=" + e.getY() + " oy=" + getRenderOffsetY()
|
||||
+ " cellH=" + cellHeight);
|
||||
boolean result = client.getInputProcessor().lightPenSelect(newAddr);
|
||||
System.out.println("LP lightPenSelect result: " + result);
|
||||
if (result) {
|
||||
refreshScreen();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -35,9 +35,9 @@ public class GocaDecoder {
|
||||
private int charHeight = 16;
|
||||
private int charSet = 0;
|
||||
private int arcParamP = 1;
|
||||
private int arcParamQ = 1;
|
||||
private int arcParamQ = 0;
|
||||
private int arcParamR = 0;
|
||||
private int arcParamS = 0;
|
||||
private int arcParamS = 1;
|
||||
|
||||
private ProgramSymbolManager programSymbolManager;
|
||||
|
||||
@@ -832,48 +832,70 @@ public class GocaDecoder {
|
||||
int centerX = curX;
|
||||
int centerY = curY;
|
||||
|
||||
// For absolute variants, read the center point from data
|
||||
if (!fromCurPos && pos + 4 <= off + len) {
|
||||
centerX = readCoord(data, pos);
|
||||
centerY = readCoord(data, pos + 2);
|
||||
pos += 4;
|
||||
}
|
||||
|
||||
double sweepFraction = 1.0;
|
||||
if (!isFull && pos + 2 <= off + len) {
|
||||
byte intPart = data[pos];
|
||||
double fracPart = (data[pos + 1] & 0xFF) / 256.0;
|
||||
sweepFraction = intPart + (intPart >= 0 ? fracPart : -fracPart);
|
||||
// Read the multiplier (integer.fraction format)
|
||||
double multiplier = 1.0;
|
||||
if (pos + 2 <= off + len) {
|
||||
int intPart = data[pos]; // signed byte
|
||||
int fracPart = data[pos + 1] & 0xFF;
|
||||
multiplier = intPart + fracPart / 256.0;
|
||||
if (multiplier == 0.0) multiplier = 1.0;
|
||||
pos += 2;
|
||||
}
|
||||
|
||||
int pxCenter = plane.mapX(centerX);
|
||||
int pyCenter = plane.mapY(centerY);
|
||||
int pxCur = plane.mapX(curX);
|
||||
int pyCur = plane.mapY(curY);
|
||||
// Compute semi-axes from arc parameters scaled by multiplier
|
||||
// P,Q and R,S are conjugate semi-diameter vectors
|
||||
double pScaled = arcParamP * multiplier;
|
||||
double qScaled = arcParamQ * multiplier;
|
||||
double rScaled = arcParamR * multiplier;
|
||||
double sScaled = arcParamS * multiplier;
|
||||
|
||||
double radius = Math.sqrt(Math.pow(pxCur - pxCenter, 2) + Math.pow(pyCur - pyCenter, 2));
|
||||
int rx = (int) Math.round(radius);
|
||||
int ry = rx;
|
||||
if (rx <= 0) {
|
||||
rx = 10;
|
||||
ry = 10;
|
||||
// Semi-axis lengths in GOCA coordinate space
|
||||
double semiAxis1 = Math.sqrt(pScaled * pScaled + qScaled * qScaled);
|
||||
double semiAxis2 = Math.sqrt(rScaled * rScaled + sScaled * sScaled);
|
||||
if (semiAxis1 < 1.0) semiAxis1 = 1.0;
|
||||
if (semiAxis2 < 1.0) semiAxis2 = 1.0;
|
||||
|
||||
// Map to pixel space
|
||||
int rx = Math.abs(plane.mapX((int) Math.round(semiAxis1)) - plane.mapX(0));
|
||||
int ry = Math.abs(plane.mapY(0) - plane.mapY((int) Math.round(semiAxis2)));
|
||||
if (rx <= 0) rx = 1;
|
||||
if (ry <= 0) ry = 1;
|
||||
|
||||
// For partial arcs, read sweep start and sweep angle
|
||||
double startAngleDeg = 0.0;
|
||||
double sweepAngleDeg = 360.0;
|
||||
if (!isFull && pos + 4 <= off + len) {
|
||||
// Sweep start: integer.fraction of full revolution
|
||||
int startInt = data[pos];
|
||||
int startFrac = data[pos + 1] & 0xFF;
|
||||
startAngleDeg = (startInt + startFrac / 256.0) * 360.0;
|
||||
pos += 2;
|
||||
// Sweep angle: integer.fraction of full revolution
|
||||
int sweepInt = data[pos];
|
||||
int sweepFrac = data[pos + 1] & 0xFF;
|
||||
sweepAngleDeg = (sweepInt + sweepFrac / 256.0) * 360.0;
|
||||
} else if (!isFull) {
|
||||
// No sweep data — default to full circle
|
||||
sweepAngleDeg = 360.0;
|
||||
}
|
||||
|
||||
double startAngleRad = Math.atan2(pyCenter - pyCur, pxCur - pxCenter);
|
||||
double startAngleDeg = Math.toDegrees(startAngleRad);
|
||||
if (startAngleDeg < 0) startAngleDeg += 360.0;
|
||||
|
||||
double sweepAngleDeg = isFull ? 360.0 : (sweepFraction * 360.0);
|
||||
System.out.println("processArc: center=(" + centerX + "," + centerY + ") mult=" + multiplier
|
||||
+ " P=" + arcParamP + " Q=" + arcParamQ + " R=" + arcParamR + " S=" + arcParamS
|
||||
+ " rx=" + rx + " ry=" + ry + " start=" + startAngleDeg + " sweep=" + sweepAngleDeg
|
||||
+ " isFull=" + isFull);
|
||||
|
||||
plane.drawArc(pxCenter, pyCenter, rx, ry, startAngleDeg, sweepAngleDeg,
|
||||
plane.drawArc(plane.mapX(centerX), plane.mapY(centerY), rx, ry, startAngleDeg, sweepAngleDeg,
|
||||
curColor, lineType, lineWidth, isFull);
|
||||
|
||||
// Arc ends at the end of the sweep
|
||||
double endAngleRad = Math.toRadians(startAngleDeg + sweepAngleDeg);
|
||||
int pxEnd = (int) Math.round(pxCenter + rx * Math.cos(endAngleRad));
|
||||
int pyEnd = (int) Math.round(pyCenter - ry * Math.sin(endAngleRad));
|
||||
|
||||
curX = plane.unmapX(pxEnd);
|
||||
curY = plane.unmapY(pyEnd);
|
||||
curX = centerX;
|
||||
curY = centerY;
|
||||
}
|
||||
|
||||
private void processFillet(byte[] data, int off, int len, boolean fromCurPos) {
|
||||
|
||||
@@ -357,16 +357,20 @@ public class InputProcessor {
|
||||
*/
|
||||
public boolean lightPenSelect(int address) {
|
||||
if (screen == null || !screen.isFormatted()) {
|
||||
System.out.println("LP: screen null or unformatted");
|
||||
return false;
|
||||
}
|
||||
int size = screen.getRows() * screen.getCols();
|
||||
int faPos = screen.findFieldAttribute(address);
|
||||
if (faPos < 0) {
|
||||
System.out.println("LP: no FA found for addr=" + address);
|
||||
return false;
|
||||
}
|
||||
|
||||
ExtendedAttribute faCell = screen.getCell(faPos);
|
||||
int fa = faCell.fa & 0xFF;
|
||||
System.out.println("LP: addr=" + address + " faPos=" + faPos + " fa=0x" + String.format("%02X", fa)
|
||||
+ " selectable=" + org.lib3270j.protocol.DS3270Constants.faIsSelectable(fa));
|
||||
if (!org.lib3270j.protocol.DS3270Constants.faIsSelectable(fa)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user