Source code: org/jempeg/empeg/emplode/dialog/EmpegScreen.java
1 /**
2 * Copyright (c) 2001, Mike Schrag & Daniel Zimmerman
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 *
11 * Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * Neither the name of Mike Schrag, Daniel Zimmerman, nor the names of any
16 * other contributors may be used to endorse or promote products derived from
17 * this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
30 */
31 package org.jempeg.empeg.emplode.dialog;
32
33 import org.jempeg.empeg.logoedit.LogoFormatUtils;
34 import org.jempeg.empeg.protocol.ProtocolClient;
35 import org.jempeg.util.Debug;
36
37 import javax.swing.JComponent;
38 import javax.swing.AbstractAction;
39
40 import java.awt.Color;
41 import java.awt.Dimension;
42 import java.awt.Graphics;
43 import java.awt.Rectangle;
44 import java.awt.event.ActionEvent;
45 import java.awt.event.WindowAdapter;
46 import java.awt.event.WindowEvent;
47 import java.awt.event.WindowListener;
48 import java.io.IOException;
49
50 /**
51 * An EmpegScreen is a renderer for the GrabScreenPacket. This basically grabs
52 * the bytes off of the Empeg's screen and displays them in a JComponent of
53 * configurable size.
54 *
55 * @author Mike Schrag
56 * @version $Revision: 1.7 $
57 */
58 public class EmpegScreen extends JComponent {
59 public static Color[] DEFAULT_COLORS = new Color[16];
60
61 static {
62 // I stepped the color faster up the grayscale, because it was _REALLY_ dark on my screen with the correct stepping
63 int step = 50;
64 for (int i = 0; i < DEFAULT_COLORS.length; i ++) {
65 DEFAULT_COLORS[i] = new Color(Math.min(i * step, 255), Math.min(i * step, 255), Math.min(i * step, 255));
66 }
67 }
68
69 private ProtocolClient myClient;
70 private Object myLock;
71 private byte[] myScreen;
72 private int myPixelSize;
73 private Color[] myColors;
74 private boolean myGrabbing;
75 private boolean myStopGrabbing;
76
77 /**
78 * Creates an EmpegScreen without grabbing, a pixel size of 2, and the default colorset (grayscale)
79 */
80 public EmpegScreen(ProtocolClient _client) throws IOException {
81 this(_client, DEFAULT_COLORS, 2, -1);
82 }
83
84 /**
85 * Creates an EmpegScreen without grabbing and with the default colorset (grayscale)
86 */
87 public EmpegScreen(ProtocolClient _client, int _pixelSize) throws IOException {
88 this(_client, DEFAULT_COLORS, _pixelSize, -1);
89 }
90
91 /**
92 * Creates an EmpegScreen with grabbing, but with the default colorset (grayscale)
93 */
94 public EmpegScreen(ProtocolClient _client, int _pixelSize, int _millisBetweenGrabs) throws IOException {
95 this(_client, DEFAULT_COLORS, _pixelSize, _millisBetweenGrabs);
96 }
97
98 /**
99 * Creates an EmpegScreen without timed grabbing
100 */
101 public EmpegScreen(ProtocolClient _client, Color[] _colors, int _pixelSize) throws IOException {
102 this(_client, _colors, _pixelSize, -1);
103 }
104
105 /**
106 * Creates an EmpegScreen. If _millisBetweenGrabs is greater than -1, then startGrabbing is automatically called.
107 *
108 * @param _client The ProtocolClient that this can use to grab the Empeg screen
109 * @param _colors A color array going from dark to light of length 16
110 * @param _pixelSize The number of pixels that each Empeg pxiel should be represented as onscreen
111 * @param _millisBetweenGrabs The number of milliseconds between each screen grab (-1 will turn off timed grabbing)
112 */
113 public EmpegScreen(ProtocolClient _client, Color[] _colors, int _pixelSize, int _millisBetweenGrabs) throws IOException {
114 this(_colors, _pixelSize);
115 myLock = new Object();
116 myClient = _client;
117 if (_millisBetweenGrabs == -1) {
118 grabScreen();
119 } else {
120 startGrabbing(_millisBetweenGrabs);
121 }
122 }
123
124 /**
125 * Creates an EmpegScreen with a prebuilt byte array.
126 *
127 * @array _screen The bytes of the screen (2048 bytes long)
128 * @array _colors A color array going from dark to light of length 16
129 * @array _pixelSize The number of pixels that each Empeg pxiel should be represented as onscreen
130 */
131 public EmpegScreen(byte[] _screen, Color[] _colors, int _pixelSize) {
132 this(_colors, _pixelSize);
133 myScreen = _screen;
134 }
135
136 protected EmpegScreen(Color[] _colors, int _pixelSize) {
137 if (_colors.length != 16) {
138 throw new RuntimeException("Color array must be exactly 16 colors long.");
139 }
140 myLock = new Object();
141 myColors = _colors;
142 myPixelSize = _pixelSize;
143 setBackground(Color.black);
144 }
145
146 /**
147 * Stops grabbing screens from the ProtocolClient
148 */
149 public void stopGrabbing() {
150 myStopGrabbing = true;
151 }
152
153 /**
154 * Starts grabbing screens from the ProtocolClient.
155 */
156 public void startGrabbing(int _millisBetweenGrabs) {
157 myGrabbing = true;
158 myStopGrabbing = false;
159 ScreenUpdater su = new ScreenUpdater(_millisBetweenGrabs);
160 Thread t = new Thread(su);
161 t.start();
162 }
163
164 /**
165 * Grabs a screen from the ProtocolClient.
166 */
167 public void grabScreen() throws IOException {
168 synchronized (myLock) {
169 myScreen = myClient.grabScreen();
170 repaint();
171 }
172 }
173
174 public void paintComponent(Graphics _g) {
175 synchronized (myLock) {
176 _g.setColor(getBackground());
177 Rectangle r = getBounds();
178 _g.fillRect(0, 0, r.width, r.height);
179 if (myScreen != null) {
180 for (int y = 0; y < 32; y ++) {
181 for (int x = 0; x < 128; x ++) {
182 int value = LogoFormatUtils.from4bpp(myScreen, x, y);
183 r.setBounds((x * myPixelSize) + x + 1, (y * myPixelSize) + y + 1, myPixelSize, myPixelSize);
184
185 _g.setColor(myColors[value]);
186 _g.fillRect(r.x, r.y, r.width, r.height);
187 }
188 }
189 }
190 }
191 }
192
193 public Dimension getPreferredSize() {
194 return new Dimension(myPixelSize * 128 + 129, myPixelSize * 32 + 33);
195 }
196
197 protected class ScreenUpdater implements Runnable {
198 private int myMillisBetweenGrabs;
199
200 public ScreenUpdater(int _millisBetweenGrabs) {
201 myMillisBetweenGrabs = _millisBetweenGrabs;
202 }
203
204 public void run() {
205 while (!myStopGrabbing) {
206 try {
207 Thread.sleep(myMillisBetweenGrabs);
208 } catch (Exception e) {
209 }
210
211 try {
212 EmpegScreen.this.grabScreen();
213 }
214 catch (IOException e) {
215 Debug.println(e);
216 }
217 }
218 myGrabbing = false;
219 }
220 }
221
222 /**
223 * Creates an AbstractAction that will regrab this EmpegScreen. Use this to easily hook
224 * the screen updating up to a JButton (for instance)
225 */
226 public AbstractAction createGrabAction() {
227 return new AbstractAction() {
228 public void actionPerformed(ActionEvent _event) {
229 try {
230 EmpegScreen.this.grabScreen();
231 }
232 catch (IOException e) {
233 Debug.println(e);
234 }
235 }
236 };
237 }
238
239 /**
240 * Creates an AbstractAction that will regrab this EmpegScreen. Use this to easily hook
241 * the screen updating up to a JButton (for instance)
242 */
243 public AbstractAction createRepeatingGrabAction() {
244 return new AbstractAction() {
245 public void actionPerformed(ActionEvent _event) {
246 if (!EmpegScreen.this.myGrabbing) {
247 EmpegScreen.this.startGrabbing(1000);
248 } else{
249 EmpegScreen.this.stopGrabbing();
250 }
251 }
252 };
253 }
254
255 /**
256 * Creates a WindowListener that will stop grabbing on shutdown.
257 */
258 public WindowListener createStopGrabbingWindowListener() {
259 return new WindowAdapter() {
260 public void windowClosed(WindowEvent _event) {
261 EmpegScreen.this.stopGrabbing();
262 }
263 };
264 }
265 }