634 lines
22 KiB
Java
634 lines
22 KiB
Java
package app;
|
|
|
|
// Java imports
|
|
import java.awt.*;
|
|
import java.awt.event.*;
|
|
import java.util.*;
|
|
import javax.swing.*;
|
|
|
|
// Project imports
|
|
import util.*;
|
|
|
|
// VIP characters window
|
|
class CharactersWindow extends ChildWindow {
|
|
|
|
// Instance fields
|
|
private int color; // Selected color index
|
|
private Point dragging; // Most recent pattern mouse position
|
|
private int index; // Current character index
|
|
private boolean grid; // Draw a grid around characters
|
|
private int palette; // Palette index
|
|
private int scale; // Display scale
|
|
private int wide; // Number of characters per row
|
|
|
|
// UI components
|
|
private JCheckBox chkGrid; // Grid check box
|
|
private UPanel client; // Client area
|
|
private UPanel panCharacters; // Characters panel
|
|
private UPanel panPalette; // Palette panel
|
|
private UPanel panPattern; // Pattern panel
|
|
private JScrollPane scrCharacters; // Characters container
|
|
private JScrollPane scrControls; // Controls panel
|
|
private JScrollBar scrWidth; // Width template scroll bar
|
|
private JSlider sldScale; // Scale slider
|
|
private JSpinner spnIndex; // Index spinner
|
|
private JSpinner spnWide; // Wide spinner
|
|
private JTextField txtAddress; // Address text box
|
|
private JTextField txtMirror; // Mirror text box
|
|
private JComboBox<String> cmbPalette; // Palette drop-down
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Constructors //
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Default constructor
|
|
CharactersWindow(MainWindow parent) {
|
|
super(parent, "characters.title");
|
|
|
|
// Configure instance fields
|
|
color = 0;
|
|
grid = true;
|
|
scale = 3;
|
|
|
|
// Template scroll bar to check control width in the current LAF
|
|
scrWidth = new JScrollBar(JScrollBar.VERTICAL);
|
|
|
|
// Configure client area
|
|
client = new UPanel(new BorderLayout());
|
|
client.setBackground(SystemColor.control);
|
|
client.setFocusable(true);
|
|
client.setPreferredSize(new Dimension(480, 360));
|
|
client.addComponentListener(Util.onResize(e->onResize()));
|
|
|
|
// Configure controls panel
|
|
var ctrls = new UPanel(new GridBagLayout());
|
|
ctrls.setBackground(SystemColor.control);
|
|
ctrls.addMouseListener(
|
|
Util.onMouse(e->client.requestFocus(), null));
|
|
scrControls = new JScrollPane(ctrls,
|
|
JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
|
|
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
|
|
scrControls.setBorder(null);
|
|
scrControls.getVerticalScrollBar().setUnitIncrement(20);
|
|
client.add(scrControls, BorderLayout.WEST);
|
|
|
|
// Character controls
|
|
label(ctrls, "characters.index", true);
|
|
spnIndex = spinner(ctrls, 0, 2047, 0, true);
|
|
spnIndex.addChangeListener(e->{
|
|
setIndex((Integer) spnIndex.getValue()); });
|
|
label(ctrls, "characters.address", false);
|
|
txtAddress = textBox(ctrls);
|
|
txtAddress.addFocusListener(Util.onFocus(null,
|
|
e->onAddress(txtAddress)));
|
|
label(ctrls, "characters.mirror", false);
|
|
txtMirror = textBox(ctrls);
|
|
txtMirror.addFocusListener(Util.onFocus(null,
|
|
e->onAddress(txtMirror)));
|
|
|
|
// Pattern panel
|
|
panPattern = new UPanel();
|
|
panPattern.setOpaque(false);
|
|
panPattern.setPreferredSize(new Dimension(96, 96));
|
|
panPattern.addMouseListener(
|
|
Util.onMouse(e->onMousePattern(e), e->onMousePattern(e)));
|
|
panPattern.addMouseMotionListener(
|
|
Util.onMouseMove(null, e->onMousePattern(e)));
|
|
panPattern.addPaintListener((g,w,h)->onPaintPattern(g, w, h));
|
|
var gbc = new GridBagConstraints();
|
|
gbc.anchor = GridBagConstraints.CENTER;
|
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
gbc.insets = new Insets(4, 2, 2, 2);
|
|
ctrls.add(panPattern, gbc);
|
|
|
|
// Palette panel
|
|
panPalette = new UPanel();
|
|
panPalette.setOpaque(false);
|
|
panPalette.setPreferredSize(new Dimension(0, 20 + 6));
|
|
panPalette.addMouseListener(
|
|
Util.onMouse(e->onMouseDownPalette(e), null));
|
|
panPalette.addPaintListener((g,w,h)->onPaintPalette(g, w, h));
|
|
gbc = new GridBagConstraints();
|
|
gbc.fill = GridBagConstraints.HORIZONTAL;
|
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
gbc.insets = new Insets(0, 2, 4, 2);
|
|
ctrls.add(panPalette, gbc);
|
|
|
|
// Fill the extra space above the view controls
|
|
var spacer = new UPanel();
|
|
spacer.setOpaque(false);
|
|
gbc = new GridBagConstraints();
|
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
gbc.weighty = 1;
|
|
ctrls.add(spacer, gbc);
|
|
|
|
// View controls
|
|
label(ctrls, "characters.grid", false);
|
|
chkGrid = checkBox(ctrls);
|
|
chkGrid.setSelected(grid);
|
|
chkGrid.addActionListener(e->{
|
|
grid = chkGrid.isSelected(); onView(); });
|
|
label(ctrls, "characters.wide", false);
|
|
spnWide = spinner(ctrls, 0, 2048, 0, false);
|
|
spnWide.addChangeListener(e->{
|
|
wide = (Integer) spnWide.getValue(); onView(); });
|
|
label(ctrls, "characters.palette", false);
|
|
cmbPalette = select(ctrls, new String[] { "palette.generic",
|
|
"palette.gplt0", "palette.gplt1", "palette.gplt2", "palette.gplt3",
|
|
"palette.jplt0", "palette.jplt1", "palette.jplt2", "palette.jplt3"
|
|
});
|
|
cmbPalette.addActionListener(e->{
|
|
palette = cmbPalette.getSelectedIndex(); repaint(); });
|
|
label(ctrls, "characters.scale", false);
|
|
sldScale = slider(ctrls, 1, 10, scale);
|
|
sldScale.addChangeListener(e->{
|
|
scale = sldScale.getValue(); onView(); });
|
|
|
|
// Terminate the list of controls
|
|
spacer = new UPanel();
|
|
spacer.setOpaque(false);
|
|
spacer.setPreferredSize(new Dimension(0, 0));
|
|
gbc = new GridBagConstraints();
|
|
gbc.gridheight = GridBagConstraints.REMAINDER;
|
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
ctrls.add(spacer, gbc);
|
|
|
|
// Configure characters panel
|
|
panCharacters = new UPanel();
|
|
panCharacters.setBackground(SystemColor.control);
|
|
panCharacters.addMouseListener(
|
|
Util.onMouse(e->onMouseDownCharacters(e), null));
|
|
panCharacters.addPaintListener((g,w,h)->onPaintCharacters(g, w, h));
|
|
scrCharacters = new JScrollPane(panCharacters);
|
|
client.add(scrCharacters, BorderLayout.CENTER);
|
|
|
|
// Configure component
|
|
setContentPane(client);
|
|
setIndex(0);
|
|
pack();
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Package Methods //
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Update the display
|
|
void refresh() {
|
|
repaint();
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Event Handlers //
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Address and Mirror text box commit
|
|
private void onAddress(JTextField src) {
|
|
int address;
|
|
|
|
// Parse the given address
|
|
try { address = (int) Long.parseLong(src.getText(), 16); }
|
|
catch (Exception e) {
|
|
setIndex(index);
|
|
return;
|
|
}
|
|
|
|
// Restrict address range
|
|
if ((address >> 24 & 7) != 0) {
|
|
setIndex(index);
|
|
return;
|
|
}
|
|
address &= 0x0007FFFF;
|
|
|
|
// Character memory
|
|
if ((address & 0x00066000) == 0x00006000)
|
|
index = address >> 15 << 9 | address >> 4 & 511;
|
|
|
|
// Mirror of character memory
|
|
else if (address >= 0x00078000)
|
|
index = address - 0x00078000 >> 4;
|
|
|
|
// Common processing
|
|
setIndex(index);
|
|
}
|
|
|
|
// Characters mouse button press
|
|
private void onMouseDownCharacters(MouseEvent e) {
|
|
|
|
// Common processing
|
|
client.requestFocus();
|
|
|
|
// Only consider left clicks
|
|
if (e.getButton() != MouseEvent.BUTTON1)
|
|
return;
|
|
|
|
// Working variables
|
|
int grid = this.grid ? 1 : 0;
|
|
int size = 8 * scale + grid;
|
|
int wide = this.wide != 0 ? this.wide :
|
|
Math.max(1, (panCharacters.getWidth() + grid) / size);
|
|
int col = e.getX() / size;
|
|
int row = e.getY() / size;
|
|
|
|
// The pixel is not within a character
|
|
if (col >= wide || row >= (2047 + wide) / wide)
|
|
return;
|
|
|
|
// Calculate the index of the selected character
|
|
int index = row * wide + col;
|
|
if (index < 2048)
|
|
setIndex(index);
|
|
}
|
|
|
|
// Palette mouse button press
|
|
private void onMouseDownPalette(MouseEvent e) {
|
|
|
|
// Common processing
|
|
client.requestFocus();
|
|
|
|
// Only consider left clicks
|
|
if (e.getButton() != MouseEvent.BUTTON1)
|
|
return;
|
|
|
|
// Working variables
|
|
int height = panPalette.getHeight();
|
|
int width = panPalette.getWidth();
|
|
int size = Math.max(1, Math.min((width - 18) / 4, height - 6));
|
|
int left = (width - size * 4 - 18) / 2;
|
|
int top = (height - size - 6) / 2;
|
|
int x = e.getX() - left - 3;
|
|
int y = e.getY() - top - 3;
|
|
|
|
// The click was not on top of a color
|
|
if (
|
|
x < 0 || x >= (size + 4) * 4 ||
|
|
x % (size + 4) >= size ||
|
|
y < 0 || y >= size
|
|
) return;
|
|
|
|
// Select the clicked color
|
|
color = x / (size + 4);
|
|
panPalette.repaint();
|
|
}
|
|
|
|
// Pattern mouse
|
|
private void onMousePattern(MouseEvent e) {
|
|
int id = e.getID();
|
|
|
|
// Mouse release
|
|
if (id == MouseEvent.MOUSE_RELEASED) {
|
|
if (e.getButton() == MouseEvent.BUTTON1)
|
|
dragging = null;
|
|
return;
|
|
}
|
|
|
|
// Mouse press
|
|
if (id == MouseEvent.MOUSE_PRESSED) {
|
|
if (e.getButton() != MouseEvent.BUTTON1)
|
|
return;
|
|
dragging = e.getPoint();
|
|
}
|
|
|
|
// Not dragging
|
|
if (dragging == null)
|
|
return;
|
|
|
|
// Configure working variables
|
|
var pix = parent.chrs[index];
|
|
var pos = e.getPoint();
|
|
int scale = Math.max(1, Math.min(
|
|
panPattern.getWidth() / 8, panPattern.getHeight() / 8));
|
|
|
|
// Determine the bounds of the line segment
|
|
int left = Math.min(dragging.x, pos.x) / scale;
|
|
int right = (Math.max(dragging.x, pos.x) - 1) / scale;
|
|
int top = Math.min(dragging.y, pos.y) / scale;
|
|
int bottom = (Math.max(dragging.y, pos.y) - 1) / scale;
|
|
if (left >= 8 || right < 0 || top >= 8 || bottom < 0) {
|
|
dragging = pos;
|
|
return;
|
|
}
|
|
|
|
// The line segment occupies a single column of pixels
|
|
if (left == right) {
|
|
top = Math.max(0, top );
|
|
bottom = Math.min(7, bottom);
|
|
|
|
// Draw the column
|
|
for (
|
|
int y = top, dest = left + top * 8;
|
|
y <= bottom;
|
|
y++, dest += 8
|
|
) pix[dest] = (byte) color;
|
|
|
|
// Update the current VRAM state
|
|
parent.encode(index);
|
|
dragging = pos;
|
|
return;
|
|
}
|
|
|
|
// Calculate and order the vertex coordinates
|
|
float v0x = (float) dragging.x / scale;
|
|
float v0y = (float) dragging.y / scale;
|
|
float v1x = (float) pos .x / scale;
|
|
float v1y = (float) pos .y / scale;
|
|
if (v0x > v1x) {
|
|
float t = v0x; v0x = v1x; v1x = t;
|
|
t = v0y; v0y = v1y; v1y = t;
|
|
}
|
|
|
|
// Determine the starting position of the line segment
|
|
float slope = (v1y - v0y) / (v1x - v0x);
|
|
float cur, next;
|
|
if (v0x < 0) {
|
|
left = 0;
|
|
cur = v0y - slope * v0x;
|
|
next = cur + slope;
|
|
} else {
|
|
cur = v0y;
|
|
next = v0y + slope * (1 - v0x % 1);
|
|
}
|
|
|
|
// Draw all columns of pixels
|
|
int last = Math.min(7, right);
|
|
for (int x = left; x <= last; x++) {
|
|
|
|
// The column is the final column in the line segment
|
|
if (x == right)
|
|
next = v1y;
|
|
|
|
// Determine the top and bottom rows of pixels
|
|
v0y = Math.max(cur, next);
|
|
if (v0y % 1 == 0)
|
|
v0y--;
|
|
top = Math.max(0, (int) Math.floor(Math.min(cur, next)));
|
|
bottom = Math.min(7, (int) Math.floor(v0y ));
|
|
|
|
// Draw the column
|
|
for (
|
|
int y = top, dest = x + top * 8;
|
|
y <= bottom;
|
|
y++, dest += 8
|
|
) pix[dest] = (byte) color;
|
|
|
|
// Advance to the next column
|
|
cur = next;
|
|
next += slope;
|
|
}
|
|
|
|
// Update the current VRAM state
|
|
parent.encode(index);
|
|
dragging = pos;
|
|
}
|
|
|
|
// Characters paint
|
|
private void onPaintCharacters(Graphics2D g, int width, int height) {
|
|
var clear = new Color(parent.app.rgbClear);
|
|
int grid = this.grid ? 1 : 0;
|
|
var pal = parent.palettes[palette][MainWindow.RED];
|
|
var pix = new byte[64];
|
|
int size = scale * 8 + grid;
|
|
int wide = this.wide != 0 ? this.wide :
|
|
Math.max(1, (width + grid) / size);
|
|
int tall = (2047 + wide) / wide;
|
|
|
|
// Draw all characters
|
|
for (int Y = 0, y = 0, z = 0; y < tall; y++, Y += size)
|
|
for (int X = 0, x = 0; x < wide; x++, z++, X += size) {
|
|
if (z == 2048)
|
|
break;
|
|
g.setColor(clear);
|
|
g.fillRect(X, Y, size - grid, size - grid);
|
|
drawCharacter(g, X, Y, scale, z, pal);
|
|
}
|
|
|
|
// Highlight the selected character
|
|
int X = index % wide * size;
|
|
int Y = index / wide * size;
|
|
int light = SystemColor.textHighlight.getRGB() & 0x00FFFFFF;
|
|
g.setColor(new Color(0xD0000000 | light, true));
|
|
g.drawRect(X , Y , 8 * scale - 1, 8 * scale - 1);
|
|
g.setColor(new Color(0x90000000 | light, true));
|
|
g.drawRect(X + 1, Y + 1, 8 * scale - 3, 8 * scale - 3);
|
|
g.setColor(new Color(0x50000000 | light, true));
|
|
g.fillRect(X + 2, Y + 2, 8 * scale - 4, 8 * scale - 4);
|
|
}
|
|
|
|
// Palette paint
|
|
private void onPaintPalette(Graphics2D g, int width, int height) {
|
|
int size = Math.max(1, Math.min((width - 18) / 4, height - 6));
|
|
int left = (width - size * 4 - 18) / 2;
|
|
var pal = parent.palettes[palette][MainWindow.RED];
|
|
int top = (height - size - 6) / 2;
|
|
|
|
// Draw the color picker
|
|
for (int x = 0; x < 4; x++, left += size + 4) {
|
|
|
|
// The current color is selected
|
|
if (x == color) {
|
|
g.setColor(SystemColor.textHighlight);
|
|
g.fillRect(left , top , size + 6, size + 6);
|
|
g.setColor(SystemColor.control);
|
|
g.fillRect(left + 2, top + 2, size + 2, size + 2);
|
|
}
|
|
|
|
// Draw the color area
|
|
g.setColor(x == 0 ? new Color(parent.app.rgbClear) : pal[x]);
|
|
g.fillRect(left + 3, top + 3, size , size );
|
|
}
|
|
|
|
}
|
|
|
|
// Pattern paint
|
|
private void onPaintPattern(Graphics2D g, int width, int height) {
|
|
int scale = Math.max(1, Math.min(width >> 3, height >> 3));
|
|
int x = (width - (scale << 3) + 1) >> 1;
|
|
int y = (height - (scale << 3) + 1) >> 1;
|
|
g.setColor(new Color(parent.app.rgbClear));
|
|
g.fillRect(x, y, scale * 8, scale * 8);
|
|
drawCharacter(g, x, y, scale, index,
|
|
parent.palettes[palette][MainWindow.RED]);
|
|
}
|
|
|
|
// Window resize
|
|
private void onResize() {
|
|
var viewport = scrControls.getViewport();
|
|
int inner = viewport.getView().getPreferredSize().width;
|
|
int outer = viewport.getExtentSize().width;
|
|
|
|
// Size the controls container to match the inner component
|
|
if (inner != outer) {
|
|
scrControls.setPreferredSize(new Dimension(
|
|
scrControls.getPreferredSize().width + inner - outer, 0));
|
|
scrControls.revalidate();
|
|
scrControls.repaint();
|
|
}
|
|
|
|
// The number of characters per row is dynamic
|
|
if (wide == 0) {
|
|
var bar = scrWidth.getPreferredSize().width;
|
|
var border = scrCharacters.getBorder();
|
|
int grid = this.grid ? 1 : 0;
|
|
var insets = border == null ? new Insets(0, 0, 0, 0) :
|
|
border.getBorderInsets(scrCharacters);
|
|
var size = new Dimension(
|
|
scrCharacters.getWidth () - insets.left - insets.right,
|
|
scrCharacters.getHeight() - insets.top - insets.bottom
|
|
);
|
|
|
|
// Calculate the dimensions without the vertical scroll bar
|
|
int wide = Math.max(1, (size.width + grid) / (8 * scale + grid));
|
|
int height = (2047 + wide) / wide * (8 * scale + grid) - grid;
|
|
|
|
// Calculate the dimensions with the vertical scroll bar
|
|
if (height > size.height) {
|
|
wide = Math.max(1, (size.width-bar+grid) / (8 * scale + grid));
|
|
height = (2047 + wide) / wide * (8 * scale + grid) - grid;
|
|
}
|
|
|
|
// Configure the component
|
|
panCharacters.setPreferredSize(
|
|
new Dimension(wide * (8 * scale + grid) - grid, height));
|
|
panCharacters.revalidate();
|
|
panCharacters.repaint();
|
|
}
|
|
|
|
}
|
|
|
|
// View control changed
|
|
private void onView() {
|
|
|
|
// Number of characters per row is dynamic: defer to resize processing
|
|
if (wide == 0) {
|
|
onResize();
|
|
return;
|
|
}
|
|
|
|
// Calculate the space occupied by the character images
|
|
int grid = this.grid ? 1 : 0;
|
|
panCharacters.setPreferredSize(new Dimension(
|
|
wide * (scale * 8 + grid) - grid,
|
|
(2047 + wide) / wide * (scale * 8 + grid) - grid
|
|
));
|
|
panCharacters.revalidate();
|
|
panCharacters.repaint();
|
|
}
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// Private Methods //
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
// Add a check box to the controls panel
|
|
private JCheckBox checkBox(UPanel panel) {
|
|
var chk = new JCheckBox();
|
|
chk.setBorder(null);
|
|
chk.setFocusable(false);
|
|
var gbc = new GridBagConstraints();
|
|
gbc.anchor = GridBagConstraints.WEST;
|
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
gbc.insets = new Insets(0, 0, 2, 2);
|
|
panel.add(chk, gbc);
|
|
return chk;
|
|
}
|
|
|
|
// Draw a character
|
|
private void drawCharacter(Graphics2D g, int X, int Y, int scale,
|
|
int index, Color[] pal) {
|
|
var pix = parent.chrs[index];
|
|
for (int y = 0, src = 0; y < 8; y++)
|
|
for (int x = 0; x < 8; x++, src++) {
|
|
if (pix[src] == 0)
|
|
continue;
|
|
g.setColor(pal[pix[src]]);
|
|
g.fillRect(X + x * scale, Y + y * scale, scale, scale);
|
|
}
|
|
}
|
|
|
|
// Add a label to the controls panel
|
|
private void label(UPanel panel, String key, boolean top) {
|
|
var lbl = new JLabel();
|
|
parent.app.localizer.add(lbl, key);
|
|
var gbc = new GridBagConstraints();
|
|
gbc.anchor = GridBagConstraints.WEST;
|
|
gbc.insets = new Insets(top ? 2 : 0, 2, 2, 2);
|
|
panel.add(lbl, gbc);
|
|
}
|
|
|
|
// Add a combo box to the controls panel
|
|
private JComboBox<String> select(UPanel panel, String[] options) {
|
|
var cmb = new JComboBox<String>();
|
|
parent.app.localizer.add(cmb, options);
|
|
cmb.setSelectedIndex(0);
|
|
var gbc = new GridBagConstraints();
|
|
gbc.fill = GridBagConstraints.BOTH;
|
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
gbc.insets = new Insets(0, 0, 1, 2);
|
|
panel.add(cmb, gbc);
|
|
return cmb;
|
|
}
|
|
|
|
// Specify the current character index
|
|
private void setIndex(int index) {
|
|
this.index = index;
|
|
spnIndex.setValue(index);
|
|
txtAddress.setText(String.format("%08X",
|
|
index >> 9 << 15 | 0x00006000 | (index & 511) << 4));
|
|
txtMirror .setText(String.format("%08X",
|
|
index << 4 | 0x00078000));
|
|
repaint();
|
|
}
|
|
|
|
// Add a slider to the controls panel
|
|
private JSlider slider(UPanel panel, int min, int max, int value) {
|
|
var sld = new JSlider(min, max, value);
|
|
sld.setFocusable(false);
|
|
sld.setPreferredSize(new Dimension(0, sld.getPreferredSize().height));
|
|
var gbc = new GridBagConstraints();
|
|
gbc.fill = GridBagConstraints.BOTH;
|
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
gbc.insets = new Insets(0, 0, 1, 2);
|
|
panel.add(sld, gbc);
|
|
return sld;
|
|
}
|
|
|
|
// Add a spinner to the controls panel
|
|
private JSpinner spinner(UPanel panel, int min, int max, int value,
|
|
boolean top) {
|
|
var spn = new JSpinner(new SpinnerNumberModel(value, min, max, 1));
|
|
var txt = new JSpinner.NumberEditor(spn, "#");
|
|
txt.getTextField().addActionListener(e->client.requestFocus());
|
|
spn.setEditor(txt);
|
|
var gbc = new GridBagConstraints();
|
|
gbc.fill = GridBagConstraints.BOTH;
|
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
gbc.insets = new Insets(top ? 2 : 0, 0, 2, 2);
|
|
gbc.weightx = 1;
|
|
panel.add(spn, gbc);
|
|
return spn;
|
|
}
|
|
|
|
// Add a text box to the controls panel
|
|
private JTextField textBox(UPanel panel) {
|
|
var txt = new JTextField();
|
|
txt.setFont(parent.app.fntMono);
|
|
txt.addActionListener(e->client.requestFocus());
|
|
var size = txt.getPreferredSize();
|
|
txt.setPreferredSize(new Dimension(
|
|
parent.app.hexDigitWidth * 8 + 2 + size.width, size.height));
|
|
var gbc = new GridBagConstraints();
|
|
gbc.fill = GridBagConstraints.BOTH;
|
|
gbc.gridwidth = GridBagConstraints.REMAINDER;
|
|
gbc.insets = new Insets(0, 0, 2, 2);
|
|
panel.add(txt, gbc);
|
|
return txt;
|
|
}
|
|
|
|
}
|