jace/src/main/java/jace/ui/EmulatorFrame.java

290 lines
10 KiB
Java

/*
* Copyright (C) 2012 Brendan Robert (BLuRry) brendan.robert@gmail.com.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301 USA
*/
package jace.ui;
import jace.core.Computer;
import java.awt.Color;
import java.awt.Component;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.event.KeyListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
/**
* A newer take on the emulator window, providing a layered user interface for
* on-screen indicator icons. Created on Mar 27, 2010, 6:40:16 PM
*
* @author Brendan Robert (BLuRry) brendan.robert@gmail.com
*/
public class EmulatorFrame extends AbstractEmulatorFrame {
@Override
public String getShortName() {
return "frame";
}
@Override
public DebuggerPanel getDebuggerPanel() {
return debuggerPanel;
}
@Override
public Component getScreen() {
return screen;
}
@Override
public void resizeVideo() {
super.resizeVideo();
layers.setLayer(screen, layers.lowestLayer());
layers.validate();
// On some systems (Ubuntu + Gnome 3) the screen layout gets messed up
// when toggling between fullscreen. This moves the screen back to the
// top of the window each time so that issue doesn't happen anymore.
screen.setLocation(screen.getLocation().x, 0);
}
public static final long serialVersionUID = -1100;
Font labelFont;
/**
* Creates new form EmulatorFrame
*/
public EmulatorFrame(Computer computer) {
setComputer(computer);
initComponents();
layers.setDoubleBuffered(true);
screen.setDoubleBuffered(true);
labelFont = Font.decode("Ubuntu-BOLD-14");
if (labelFont == null) {
labelFont = Font.decode("Arial-BOLD-14");
}
layers.setBounds(getContentPane().getBounds());
screen.setBounds(layers.getBounds());
debuggerPanel.setVisible(false);
layers.setPosition(screen, 10);
layers.setPosition(debuggerPanel, 2);
reconfigure();
screen.setFocusTraversalKeysEnabled(false);
}
@Override
public synchronized void addKeyListener(KeyListener l) {
super.addKeyListener(l);
layers.addKeyListener(l);
screen.addKeyListener(l);
}
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
layers = new javax.swing.JLayeredPane();
screen = new jace.ui.ScreenPanel();
debuggerPanel = new jace.ui.DebuggerPanel();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setBackground(new java.awt.Color(0, 0, 0));
setCursor(new java.awt.Cursor(java.awt.Cursor.DEFAULT_CURSOR));
layers.setBackground(new java.awt.Color(0, 0, 64));
layers.setOpaque(true);
javax.swing.GroupLayout screenLayout = new javax.swing.GroupLayout(screen);
screen.setLayout(screenLayout);
screenLayout.setHorizontalGroup(
screenLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 560, Short.MAX_VALUE)
);
screenLayout.setVerticalGroup(
screenLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(0, 520, Short.MAX_VALUE)
);
screen.setBounds(0, 0, 560, 520);
layers.add(screen, javax.swing.JLayeredPane.DEFAULT_LAYER);
debuggerPanel.setBounds(460, 0, 100, 492);
layers.add(debuggerPanel, javax.swing.JLayeredPane.MODAL_LAYER);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(layers, javax.swing.GroupLayout.DEFAULT_SIZE, 560, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(layers, javax.swing.GroupLayout.DEFAULT_SIZE, 518, Short.MAX_VALUE)
);
pack();
}// </editor-fold>//GEN-END:initComponents
/**
* @param args the command line arguments
*/
public static void main(String args[]) {
java.awt.EventQueue.invokeLater(() -> {
new EmulatorFrame(null).setVisible(true);
});
}
// Variables declaration - do not modify//GEN-BEGIN:variables
public jace.ui.DebuggerPanel debuggerPanel;
public javax.swing.JLayeredPane layers;
public jace.ui.ScreenPanel screen;
// End of variables declaration//GEN-END:variables
Set<JLabel> previousIndicators = new HashSet<>();
@Override
public void doRedrawIndicators(Set<ImageIcon> ind) {
synchronized (previousIndicators) {
previousIndicators.stream().map((l) -> {
l.setVisible(false);
return l;
}).forEach((l) -> {
layers.remove(l);
});
previousIndicators.clear();
}
if (ind != null && !ind.isEmpty()) {
int x = layers.getWidth();
int y = layers.getHeight();
for (ImageIcon i : visibleIndicators) {
JLabel label = createIndicatorIcon(i);
x -= (i.getIconWidth() + 10);
layers.add(label);
layers.setLayer(label, layers.highestLayer());
label.setBounds(x, y - i.getIconHeight() - 10, i.getIconWidth() + 5, i.getIconHeight() + 5);
if (x <= 80) {
x = layers.getWidth();
y -= 140;
}
synchronized (previousIndicators) {
previousIndicators.add(label);
}
label.setVisible(true);
}
} else {
if (computer != null && computer.video != null) {
computer.video.forceRefresh();
}
// This was causing a whole screen flicker -- bad.
// screen.repaint();
}
screen.requestFocusInWindow();
}
@Override
public void repaintIndicators() {
synchronized (previousIndicators) {
if (previousIndicators != null) {
previousIndicators.stream().forEach((l) -> {
Graphics g = l.getGraphics();
if (g != null) {
l.paint(g);
}
});
}
}
}
Map<ImageIcon, JLabel> indicatorCache = new HashMap<>();
private JLabel createIndicatorIcon(ImageIcon i) {
if (indicatorCache.containsKey(i)) {
return indicatorCache.get(i);
}
JLabel label = new OutlinedLabel(i.getDescription());
label.setIcon(i);
label.setHorizontalTextPosition(JLabel.CENTER);
label.setVerticalTextPosition(JLabel.CENTER);
label.setBackground(Color.BLACK);
label.setForeground(Color.WHITE);
label.setFont(labelFont);
label.setOpaque(false);
label.setFocusable(false);
label.setBounds(0, 0, i.getIconWidth(), i.getIconHeight());
BufferedImage img = new BufferedImage(i.getIconWidth(), i.getIconHeight(), BufferedImage.TYPE_INT_ARGB);
label.paint(img.getGraphics());
ImageIcon icon = new ImageIcon(img);
JLabel renderedLabel = new JLabel(icon);
indicatorCache.put(i, renderedLabel);
return renderedLabel;
}
Map<String, JFrame> modals = new HashMap<>();
@Override
protected void displayModalDialog(final String name, JPanel ui, List<String> ancestors) {
final JFrame modal = modals.get(name);
if (modal != null) {
modal.setVisible(true);
modal.setState(Frame.NORMAL);
modal.toFront();
modal.requestFocus();
return;
}
JFrame frame = new JFrame();
modals.put(name, frame);
frame.addWindowStateListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
closeDialog(name);
}
});
frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
frame.setTitle(name);
frame.setContentPane(ui);
frame.setSize(ui.getPreferredSize());
frame.validate();
frame.setVisible(true);
}
@Override
protected void disposeModalDialog(String name) {
JFrame modal = modals.get(name);
if (modal != null) {
modals.remove(name);
modal.dispose();
}
modals.remove(name);
}
@Override
protected void hideModalDialog(String name) {
JFrame modal = modals.get(name);
if (modal != null) {
modal.setVisible(false);
}
}
}