├── .travis.yml
├── dist
└── asciiPanel.jar
├── src
├── main
│ ├── resources
│ │ ├── cp437.png
│ │ ├── cp437_8x8.png
│ │ ├── cp437_10x10.png
│ │ ├── cp437_12x12.png
│ │ ├── cp437_16x16.png
│ │ ├── cp437_9x16.png
│ │ ├── drake_10x10.png
│ │ ├── qbicfeet_10x10.png
│ │ ├── taffer_10x10.png
│ │ └── talryth_square_15x15.png
│ └── java
│ │ └── asciiPanel
│ │ ├── TileTransformer.java
│ │ ├── AsciiCharacterData.java
│ │ ├── AsciiFont.java
│ │ └── AsciiPanel.java
└── test
│ ├── resources
│ └── cp437.png
│ └── java
│ └── asciiPanel
│ └── AsciiPanelTest.java
├── LICENSE.md
├── .gitignore
├── pom.xml
└── README.MD
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: java
2 | jdk:
3 | - oraclejdk8
4 |
--------------------------------------------------------------------------------
/dist/asciiPanel.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trystan/AsciiPanel/HEAD/dist/asciiPanel.jar
--------------------------------------------------------------------------------
/src/main/resources/cp437.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trystan/AsciiPanel/HEAD/src/main/resources/cp437.png
--------------------------------------------------------------------------------
/src/test/resources/cp437.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trystan/AsciiPanel/HEAD/src/test/resources/cp437.png
--------------------------------------------------------------------------------
/src/main/resources/cp437_8x8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trystan/AsciiPanel/HEAD/src/main/resources/cp437_8x8.png
--------------------------------------------------------------------------------
/src/main/resources/cp437_10x10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trystan/AsciiPanel/HEAD/src/main/resources/cp437_10x10.png
--------------------------------------------------------------------------------
/src/main/resources/cp437_12x12.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trystan/AsciiPanel/HEAD/src/main/resources/cp437_12x12.png
--------------------------------------------------------------------------------
/src/main/resources/cp437_16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trystan/AsciiPanel/HEAD/src/main/resources/cp437_16x16.png
--------------------------------------------------------------------------------
/src/main/resources/cp437_9x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trystan/AsciiPanel/HEAD/src/main/resources/cp437_9x16.png
--------------------------------------------------------------------------------
/src/main/resources/drake_10x10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trystan/AsciiPanel/HEAD/src/main/resources/drake_10x10.png
--------------------------------------------------------------------------------
/src/main/resources/qbicfeet_10x10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trystan/AsciiPanel/HEAD/src/main/resources/qbicfeet_10x10.png
--------------------------------------------------------------------------------
/src/main/resources/taffer_10x10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trystan/AsciiPanel/HEAD/src/main/resources/taffer_10x10.png
--------------------------------------------------------------------------------
/src/main/resources/talryth_square_15x15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/trystan/AsciiPanel/HEAD/src/main/resources/talryth_square_15x15.png
--------------------------------------------------------------------------------
/src/main/java/asciiPanel/TileTransformer.java:
--------------------------------------------------------------------------------
1 | package asciiPanel;
2 |
3 | public interface TileTransformer {
4 | public void transformTile(int x, int y, AsciiCharacterData data);
5 | }
--------------------------------------------------------------------------------
/src/main/java/asciiPanel/AsciiCharacterData.java:
--------------------------------------------------------------------------------
1 | package asciiPanel;
2 |
3 | import java.awt.Color;
4 |
5 | public class AsciiCharacterData {
6 | public AsciiCharacterData() {}
7 |
8 | public AsciiCharacterData(char character, Color foregroundColor, Color backgroundColor) {
9 | this.character = character;
10 | this.foregroundColor = foregroundColor;
11 | this.backgroundColor = backgroundColor;
12 | }
13 |
14 | public char character;
15 | public Color foregroundColor;
16 | public Color backgroundColor;
17 | }
18 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Trystan Spangler
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 |
3 | # Mobile Tools for Java (J2ME)
4 | .mtj.tmp/
5 |
6 | # Package Files #
7 | *.jar
8 | *.war
9 | *.ear
10 |
11 | # Maven build directory
12 | target/
13 |
14 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
15 | hs_err_pid*
16 |
17 | # Eclipse created files and directories
18 | .classpath
19 | .project
20 | .settings
21 |
22 | # =========================
23 | # Operating System Files
24 | # =========================
25 |
26 | # OSX
27 | # =========================
28 |
29 | .DS_Store
30 | .AppleDouble
31 | .LSOverride
32 |
33 | # Thumbnails
34 | ._*
35 |
36 | # Files that might appear in the root of a volume
37 | .DocumentRevisions-V100
38 | .fseventsd
39 | .Spotlight-V100
40 | .TemporaryItems
41 | .Trashes
42 | .VolumeIcon.icns
43 |
44 | # Directories potentially created on remote AFP share
45 | .AppleDB
46 | .AppleDesktop
47 | Network Trash Folder
48 | Temporary Items
49 | .apdisk
50 |
51 | # Windows
52 | # =========================
53 |
54 | # Windows image file caches
55 | Thumbs.db
56 | ehthumbs.db
57 |
58 | # Folder config file
59 | Desktop.ini
60 |
61 | # Recycle Bin used on file shares
62 | $RECYCLE.BIN/
63 |
64 | # Windows Installer files
65 | *.cab
66 | *.msi
67 | *.msm
68 | *.msp
69 |
70 | # Windows shortcuts
71 | *.lnk
72 |
--------------------------------------------------------------------------------
/src/main/java/asciiPanel/AsciiFont.java:
--------------------------------------------------------------------------------
1 | package asciiPanel;
2 |
3 | /**
4 | * This class holds provides all available Fonts for the AsciiPanel.
5 | * Some graphics are from the Dwarf Fortress Tileset Wiki Page
6 | *
7 | * @author zn80
8 | *
9 | */
10 | public class AsciiFont {
11 |
12 | public static final AsciiFont CP437_8x8 = new AsciiFont("cp437_8x8.png", 8, 8);
13 | public static final AsciiFont CP437_10x10 = new AsciiFont("cp437_10x10.png", 10, 10);
14 | public static final AsciiFont CP437_12x12 = new AsciiFont("cp437_12x12.png", 12, 12);
15 | public static final AsciiFont CP437_16x16 = new AsciiFont("cp437_16x16.png", 16, 16);
16 | public static final AsciiFont CP437_9x16 = new AsciiFont("cp437_9x16.png", 9, 16);
17 | public static final AsciiFont DRAKE_10x10 = new AsciiFont("drake_10x10.png", 10, 10);
18 | public static final AsciiFont TAFFER_10x10 = new AsciiFont("taffer_10x10.png", 10, 10);
19 | public static final AsciiFont QBICFEET_10x10 = new AsciiFont("qbicfeet_10x10.png", 10, 10);
20 | public static final AsciiFont TALRYTH_15_15 = new AsciiFont("talryth_square_15x15.png", 15, 15);
21 |
22 | private String fontFilename;
23 |
24 | public String getFontFilename() {
25 | return fontFilename;
26 | }
27 |
28 | private int width;
29 |
30 | public int getWidth() {
31 | return width;
32 | }
33 |
34 | private int height;
35 |
36 | public int getHeight() {
37 | return height;
38 | }
39 |
40 | public AsciiFont(String filename, int width, int height) {
41 | this.fontFilename = filename;
42 | this.width = width;
43 | this.height = height;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
4 | 4.0.0
5 |
6 | net.trystan
7 | ascii-panel
8 | 1.2-SNAPSHOT
9 |
10 |
11 | UTF-8
12 | 1.8
13 | 1.8
14 |
15 |
16 |
17 |
18 | junit
19 | junit
20 | 4.13.1
21 | test
22 |
23 |
24 | org.powermock
25 | powermock-module-junit4
26 | 1.6.5
27 | test
28 |
29 |
30 | org.powermock
31 | powermock-api-mockito
32 | 1.6.5
33 | test
34 |
35 |
36 |
37 |
38 |
39 |
40 | org.apache.maven.plugins
41 | maven-source-plugin
42 | 3.0.1
43 |
44 |
45 | attach-sources
46 |
47 | jar
48 |
49 |
50 |
51 |
52 |
53 | org.apache.maven.plugins
54 | maven-javadoc-plugin
55 | 3.0.0-M1
56 |
57 | -Xdoclint:none
58 | true
59 |
60 |
61 |
62 | attach-javadocs
63 |
64 | jar
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
--------------------------------------------------------------------------------
/README.MD:
--------------------------------------------------------------------------------
1 | # AsciiPanel
2 |
3 | [](https://travis-ci.org/roddy/MavenizedAsciiPanel)
4 |
5 | AsciiPanel simulates a [code page 437](https://en.wikipedia.org/wiki/Code_page_437) ASCII terminal display. It supports all 256 characters of codepage 437, arbitrary foreground colors, arbitrary background colors, and arbitrary terminal sizes.
6 |
7 | The default terminal size is 80x24 characters and default colors matching the Windows Command Prompt are provided. The default font is 9x16 pixel CP437 (`CP437_9x16`.)
8 |
9 | This should be useful to roguelike developers.
10 |
11 | ## Usage
12 |
13 | AsciiPanel supports the customization of fonts. The following system fonts are provided:
14 | - CP437_9x16
15 | - CP437_8x8
16 | - CP437_10x10
17 | - CP437_12x12
18 | - CP437_16x16
19 |
20 | In addition, the following fontsets from the [Dwarf Fortress Tileset](http://dwarffortresswiki.org/Tileset_repository) are also included:
21 | - DRAKE_10x10
22 | - QBICFEET_10x10
23 | - TALRYTH_15x15
24 |
25 | The AsciiPanel class provides a special three-parameter constructor to support font customization. Simply pass the desired AsciiFont as the third parameter as follows.
26 |
27 | ```java
28 | AsciiPanel myPanel = new AsciiPanel(80, 24, AsciiFont.DRAKE_10x10);
29 |
30 | ```
31 |
32 | ## Demo
33 |
34 | Small demo of AsciiPanel.
35 | ```java
36 | import asciiPanel.AsciiFont;
37 | import asciiPanel.AsciiPanel;
38 |
39 | import javax.swing.*;
40 | import java.awt.*;
41 | import java.util.Random;
42 |
43 | public class Demo {
44 | // Declare variables for the AsciiPanel terminal, JFrame, random generator, and the title string
45 | private static AsciiPanel terminal;
46 | private static JFrame frame;
47 | private static Random rand;
48 | private static String TITLE = "Demo AsciiPanel";
49 |
50 | public static void main(String[] args) {
51 | // Initialize the frame, terminal, and random number generator
52 | // JFrame is the container for the terminal
53 | frame = new JFrame(TITLE); // Create a new JFrame with the title "Demo AsciiPanel"
54 | terminal = new AsciiPanel(); // Create a new AsciiPanel instance (the terminal)
55 | rand = new Random(); // Initialize the random generator for background color selection
56 |
57 | // Write the title in the center of the terminal at row 2
58 | terminal.writeCenter(TITLE, 2);
59 |
60 | // Write the text "Red color" in red at row 5
61 | terminal.writeCenter("Red color", 5, AsciiPanel.red);
62 |
63 | // Random generation loop: write spaces with random background colors
64 | // Iterate through a specific region (from x = 15 to 45, y = 10 to 20)
65 | for (int x = 15; x < 45; x++) {
66 | for (int y = 10; y < 20; y++) {
67 | // Randomly choose a background color (either blue or green)
68 | if (rand.nextInt(2) == 0) {
69 | terminal.setDefaultBackgroundColor(AsciiPanel.blue); // Set background color to blue
70 | } else {
71 | terminal.setDefaultBackgroundColor(AsciiPanel.green); // Set background color to green
72 | }
73 |
74 | // Write a space character (" ") at the current position (x, y) with the selected background color
75 | terminal.write(" ", x, y);
76 | }
77 | }
78 |
79 | // Add the terminal to the frame
80 | // Set the frame properties: make it non-resizable, pack it to fit the terminal, and set default close operation
81 | frame.add(terminal);
82 | frame.setResizable(false); // Disable resizing of the window
83 | frame.pack(); // Adjust the window size to fit the terminal size
84 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // Ensure the application exits when the window is closed
85 | frame.setVisible(true); // Make the window visible to the user
86 | }
87 | }
88 | ```
89 |
90 | ## Build instructions
91 |
92 | AsciiPanel is a [Maven](https://maven.apache.org/) project, compatible with Maven 2 and Maven 3. It can be built using the following command:
93 |
94 | ```
95 | mvn install
96 | ```
97 |
98 | This will build the project, run the unit tests, and copy the resulting jar into your local Maven repository. Once the jar is deployed to your repository, you can include it in your projects by including the following dependency in your pom:
99 |
100 | ```xml
101 |
102 | net.trystan
103 | ascii-panel
104 | 1.1
105 |
106 | ```
107 |
108 | Or you can add the jitpack repository to your pom:
109 |
110 | ```xml
111 |
112 | jitpack.io
113 | https://jitpack.io
114 |
115 | ```
116 |
117 | which provides AsciiPanel as dependency at:
118 |
119 | ```xml
120 |
121 | com.github.trystan
122 | AsciiPanel
123 | 31bc98d
124 |
125 | ```
126 |
127 | where `` describes the git commit you want to use.
128 |
129 | For Gradle users:
130 |
131 | ```gradle
132 | repositories {
133 | //...
134 | allprojects {
135 | repositories {
136 | maven { url 'https://jitpack.io' }
137 | }
138 | }
139 | }
140 |
141 | dependencies {
142 | //...
143 | compile 'com.github.trystan:AsciiPanel:master-SNAPSHOT'
144 | }
145 | ```
146 |
147 | ## Notes
148 |
149 | This project is built with Java 8. However the code itself does not *require* Java 8. If you are supporting a project running an earlier version of Java, you can change the pom file and rebuild the jar using your chosen version of Java without having to modify the code.
150 |
--------------------------------------------------------------------------------
/src/test/java/asciiPanel/AsciiPanelTest.java:
--------------------------------------------------------------------------------
1 | package asciiPanel;
2 |
3 | import java.awt.*;
4 | import java.awt.image.BufferedImage;
5 | import java.io.File;
6 | import java.io.IOException;
7 | import javax.imageio.ImageIO;
8 | import javax.swing.JComponent;
9 | import javax.swing.UIManager;
10 | import javax.swing.plaf.PanelUI;
11 | import org.junit.runner.RunWith;
12 | import org.junit.Before;
13 | import org.junit.Test;
14 | import org.powermock.api.mockito.PowerMockito;
15 | import org.powermock.core.classloader.annotations.PowerMockIgnore;
16 | import org.powermock.core.classloader.annotations.PrepareForTest;
17 | import org.powermock.modules.junit4.PowerMockRunner;
18 |
19 | import static org.junit.Assert.*;
20 | import static org.mockito.Mockito.*;
21 |
22 | @RunWith( PowerMockRunner.class )
23 | @PrepareForTest({ UIManager.class, ImageIO.class })
24 | @PowerMockIgnore("javax.swing.*")
25 | public class AsciiPanelTest {
26 |
27 | @Before
28 | public void initMocks() throws IOException {
29 | PowerMockito.mockStatic(UIManager.class);
30 | PowerMockito.mockStatic(ImageIO.class);
31 |
32 | BufferedImage mockImage = mock(BufferedImage.class);
33 | PanelUI mockPanelUi = mock(PanelUI.class);
34 |
35 | when(UIManager.getUI(any(JComponent.class)))
36 | .thenReturn(mockPanelUi);
37 |
38 | when(ImageIO.read(any(File.class)))
39 | .thenReturn(mockImage);
40 | }
41 |
42 | @Test( expected = IllegalArgumentException.class )
43 | public void testSetNegativeCursorX() {
44 | AsciiPanel panel = new AsciiPanel();
45 | panel.setCursorX(-1);
46 |
47 | fail("Should have thrown an IllegalArgumentException.");
48 | }
49 |
50 | @Test( expected = IllegalArgumentException.class )
51 | public void testSetCursorXOutsideOfMax() {
52 | AsciiPanel panel = new AsciiPanel();
53 | panel.setCursorX(Integer.MAX_VALUE);
54 |
55 | fail("Should have thrown an IllegalArgumentException.");
56 | }
57 |
58 | @Test( expected = IllegalArgumentException.class )
59 | public void testSetNegativeCursorY() {
60 | AsciiPanel panel = new AsciiPanel();
61 | panel.setCursorY(-1);
62 |
63 | fail("Should have thrown an IllegalArgumentException.");
64 | }
65 |
66 | @Test( expected = IllegalArgumentException.class )
67 | public void testSetCursorYOutsideOfMax() {
68 | AsciiPanel panel = new AsciiPanel();
69 | panel.setCursorY(Integer.MAX_VALUE);
70 |
71 | fail("Should have thrown an IllegalArgumentException.");
72 | }
73 |
74 | @Test
75 | public void testSetCursorX() {
76 | AsciiPanel panel = new AsciiPanel(1, 1);
77 | panel.setCursorX(0);
78 | }
79 |
80 | @Test
81 | public void testSetCursorY() {
82 | AsciiPanel panel = new AsciiPanel(1, 1);
83 | panel.setCursorY(0);
84 | }
85 |
86 | @Test( expected = NullPointerException.class )
87 | public void testSetNullDefaultBackgroundColor() {
88 | AsciiPanel panel = new AsciiPanel();
89 | panel.setDefaultBackgroundColor(null);
90 |
91 | fail("Should have thrown a NullPointerException.");
92 | }
93 |
94 | @Test( expected = NullPointerException.class )
95 | public void testSetNullDefaultForegroundColor() {
96 | AsciiPanel panel = new AsciiPanel();
97 | panel.setDefaultForegroundColor(null);
98 |
99 | fail("Should have thrown a NullPointerException.");
100 | }
101 |
102 | @Test( expected = IllegalArgumentException.class )
103 | public void testConstructorZeroWidth() {
104 | new AsciiPanel(0, 24);
105 |
106 | fail("Should have thrown an IllegalArgumentException.");
107 | }
108 |
109 | @Test( expected = IllegalArgumentException.class )
110 | public void testConstructorZeroHeight() {
111 | new AsciiPanel(80, 0);
112 |
113 | fail("Should have thrown an IllegalArgumentException.");
114 | }
115 |
116 | @Test( expected = NullPointerException.class )
117 | public void testWriteNullFail() {
118 | AsciiPanel panel = new AsciiPanel(80, 1);
119 | panel.write(null);
120 | fail("Should have thrown a NullPointerException.");
121 | }
122 |
123 | @Test( expected = IllegalArgumentException.class )
124 | public void testWriteInvalidLengthFail() {
125 | AsciiPanel panel = new AsciiPanel(80, 1);
126 | String superLongString = String.format("%0100d", 1);
127 | panel.write(superLongString);
128 | fail("Should have thrown an IllegalArgumentException.");
129 | }
130 |
131 | @Test
132 | public void testWriteChar() {
133 | AsciiPanel panel = new AsciiPanel(1, 1);
134 | panel.write(' ');
135 | }
136 |
137 | @Test
138 | public void testWriteCharFG() {
139 | AsciiPanel panel = new AsciiPanel(1, 1);
140 | panel.write(' ', AsciiPanel.white);
141 | }
142 |
143 | @Test
144 | public void testWriteCharFGBG() {
145 | AsciiPanel panel = new AsciiPanel(1, 1);
146 | panel.write(' ', AsciiPanel.white, AsciiPanel.black);
147 | }
148 |
149 | @Test
150 | public void testWriteCharXY() {
151 | AsciiPanel panel = new AsciiPanel(1, 1);
152 | panel.write(' ', 0, 0);
153 | }
154 |
155 | @Test
156 | public void testWriteCharXYFG() {
157 | AsciiPanel panel = new AsciiPanel(1, 1);
158 | panel.write(' ', 0, 0, AsciiPanel.white);
159 | }
160 |
161 | @Test
162 | public void testWriteCharXYFGBG() {
163 | AsciiPanel panel = new AsciiPanel(1, 1);
164 | panel.write(' ', 0, 0, AsciiPanel.white, AsciiPanel.black);
165 | }
166 |
167 | @Test
168 | public void testWriteString() {
169 | AsciiPanel panel = new AsciiPanel(1, 1);
170 | panel.write(" ");
171 | }
172 |
173 | @Test
174 | public void testWriteStringFG() {
175 | AsciiPanel panel = new AsciiPanel(1, 1);
176 | panel.write(" ", AsciiPanel.white);
177 | }
178 |
179 | @Test
180 | public void testWriteStringFGBG() {
181 | AsciiPanel panel = new AsciiPanel(1, 1);
182 | panel.write(" ", AsciiPanel.white, AsciiPanel.black);
183 | }
184 |
185 | @Test
186 | public void testWriteStringXY() {
187 | AsciiPanel panel = new AsciiPanel(1, 1);
188 | panel.write(" ", 0, 0);
189 | }
190 |
191 | @Test
192 | public void testWriteStringXYFG() {
193 | AsciiPanel panel = new AsciiPanel(1, 1);
194 | panel.write(" ", 0, 0, AsciiPanel.white);
195 | }
196 |
197 | @Test
198 | public void testWriteStringXYFGBG() {
199 | AsciiPanel panel = new AsciiPanel(1, 1);
200 | panel.write(" ", 0, 0, AsciiPanel.white, AsciiPanel.black);
201 | }
202 |
203 | @Test
204 | public void testWriteCenter() {
205 | AsciiPanel panel = new AsciiPanel(1, 1);
206 | panel.writeCenter(" ", 0);
207 | }
208 |
209 | @Test
210 | public void testWriteCenterFG() {
211 | AsciiPanel panel = new AsciiPanel(1, 1);
212 | panel.writeCenter(" ", 0, AsciiPanel.white);
213 | }
214 |
215 | @Test
216 | public void testWriteCenterFGBG() {
217 | AsciiPanel panel = new AsciiPanel(1, 1);
218 | panel.writeCenter(" ", 0, AsciiPanel.white, AsciiPanel.black);
219 | }
220 |
221 | @Test
222 | public void testSetAsciiFont()
223 | {
224 | AsciiPanel panel = new AsciiPanel(1, 1, AsciiFont.CP437_9x16);
225 | Dimension oldDimensions = panel.getPreferredSize();
226 |
227 | panel.setAsciiFont(AsciiFont.TALRYTH_15_15);
228 | Dimension newDimensions = panel.getPreferredSize();
229 |
230 | assertNotEquals(oldDimensions, newDimensions);
231 | }
232 |
233 | @Test
234 | public void testWrite() {
235 | int width = 100;
236 | int height = 100;
237 | AsciiPanel panel = new AsciiPanel(width, height);
238 |
239 | // write out characters in a specific pattern such that we can verify each is written correctly to the specified
240 | // position
241 | Color oddColumnForeground = new Color(255, 255, 255);
242 | Color evenColumnForeground = new Color(0, 0, 0);
243 | Color oddRowBackground = new Color(255, 255, 0);
244 | Color evenRowBackground = new Color(0, 255, 255);
245 |
246 | AsciiCharacterData[][] expectedCharacterData = new AsciiCharacterData[width][height];
247 |
248 | for (int x = 0; x < width; x++) {
249 | for (int y = 0; y < width; y++) {
250 | AsciiCharacterData characterData = new AsciiCharacterData();
251 | characterData.character = (char)(x + y);
252 | if (x % 2 == 0) {
253 | characterData.foregroundColor = evenColumnForeground;
254 | } else {
255 | characterData.foregroundColor = oddColumnForeground;
256 | }
257 |
258 | if (y % 2 == 0) {
259 | characterData.backgroundColor = evenRowBackground;
260 | } else {
261 | characterData.backgroundColor = oddRowBackground;
262 | }
263 | panel.write(characterData, x, y);
264 | expectedCharacterData[x][y] = characterData;
265 | }
266 | }
267 |
268 | // now validate that it was written as expected
269 | AsciiCharacterData[][] writtenData = panel.getCharacters();
270 | for (int x = 0; x < width; x++) {
271 | for (int y = 0; y < height; y++) {
272 | AsciiCharacterData expectedCharData = expectedCharacterData[x][y];
273 | AsciiCharacterData writtenCharData = writtenData[x][y];
274 | assertEquals(expectedCharData.character, writtenCharData.character);
275 | assertEquals(expectedCharData.foregroundColor, writtenCharData.foregroundColor);
276 | assertEquals(expectedCharData.backgroundColor, writtenCharData.backgroundColor);
277 | }
278 | }
279 | }
280 | }
281 |
--------------------------------------------------------------------------------
/src/main/java/asciiPanel/AsciiPanel.java:
--------------------------------------------------------------------------------
1 | package asciiPanel;
2 |
3 | import java.awt.Color;
4 | import java.awt.Dimension;
5 | import java.awt.Graphics;
6 | import java.awt.Image;
7 | import java.awt.image.BufferedImage;
8 | import java.awt.image.LookupOp;
9 | import java.awt.image.ShortLookupTable;
10 | import java.io.IOException;
11 |
12 | import javax.imageio.ImageIO;
13 | import javax.swing.JPanel;
14 |
15 | /**
16 | * This simulates a code page 437 ASCII terminal display.
17 | * @author Trystan Spangler
18 | */
19 | public class AsciiPanel extends JPanel {
20 | private static final long serialVersionUID = -4167851861147593092L;
21 |
22 | /**
23 | * The color black (pure black).
24 | */
25 | public static Color black = new Color(0, 0, 0);
26 |
27 | /**
28 | * The color red.
29 | */
30 | public static Color red = new Color(128, 0, 0);
31 |
32 | /**
33 | * The color green.
34 | */
35 | public static Color green = new Color(0, 128, 0);
36 |
37 | /**
38 | * The color yellow.
39 | */
40 | public static Color yellow = new Color(128, 128, 0);
41 |
42 | /**
43 | * The color blue.
44 | */
45 | public static Color blue = new Color(0, 0, 128);
46 |
47 | /**
48 | * The color magenta.
49 | */
50 | public static Color magenta = new Color(128, 0, 128);
51 |
52 | /**
53 | * The color cyan.
54 | */
55 | public static Color cyan = new Color(0, 128, 128);
56 |
57 | /**
58 | * The color white (light gray).
59 | */
60 | public static Color white = new Color(192, 192, 192);
61 |
62 | /**
63 | * A brighter black (dark gray).
64 | */
65 | public static Color brightBlack = new Color(128, 128, 128);
66 |
67 | /**
68 | * A brighter red.
69 | */
70 | public static Color brightRed = new Color(255, 0, 0);
71 |
72 | /**
73 | * A brighter green.
74 | */
75 | public static Color brightGreen = new Color(0, 255, 0);
76 |
77 | /**
78 | * A brighter yellow.
79 | */
80 | public static Color brightYellow = new Color(255, 255, 0);
81 |
82 | /**
83 | * A brighter blue.
84 | */
85 | public static Color brightBlue = new Color(0, 0, 255);
86 |
87 | /**
88 | * A brighter magenta.
89 | */
90 | public static Color brightMagenta = new Color(255, 0, 255);
91 |
92 | /**
93 | * A brighter cyan.
94 | */
95 | public static Color brightCyan = new Color(0, 255, 255);
96 |
97 | /**
98 | * A brighter white (pure white).
99 | */
100 | public static Color brightWhite = new Color(255, 255, 255);
101 |
102 | private Image offscreenBuffer;
103 | private Graphics offscreenGraphics;
104 | private int widthInCharacters;
105 | private int heightInCharacters;
106 | private int charWidth = 9;
107 | private int charHeight = 16;
108 | private String terminalFontFile = "cp437_9x16.png";
109 | private Color defaultBackgroundColor;
110 | private Color defaultForegroundColor;
111 | private int cursorX;
112 | private int cursorY;
113 | private BufferedImage glyphSprite;
114 | private BufferedImage[] glyphs;
115 | private AsciiCharacterData[][] characters;
116 | private AsciiCharacterData[][] previousCharacters;
117 | private AsciiFont asciiFont;
118 |
119 | /**
120 | * Gets the height, in pixels, of a character.
121 | * @return
122 | */
123 | public int getCharHeight() {
124 | return charHeight;
125 | }
126 |
127 | /**
128 | * Gets the width, in pixels, of a character.
129 | * @return
130 | */
131 | public int getCharWidth() {
132 | return charWidth;
133 | }
134 |
135 | /**
136 | * Gets the height in characters.
137 | * A standard terminal is 24 characters high.
138 | * @return
139 | */
140 | public int getHeightInCharacters() {
141 | return heightInCharacters;
142 | }
143 |
144 | /**
145 | * Gets the width in characters.
146 | * A standard terminal is 80 characters wide.
147 | * @return
148 | */
149 | public int getWidthInCharacters() {
150 | return widthInCharacters;
151 | }
152 |
153 | /**
154 | * Gets the distance from the left new text will be written to.
155 | * @return
156 | */
157 | public int getCursorX() {
158 | return cursorX;
159 | }
160 |
161 | /**
162 | * Sets the distance from the left new text will be written to.
163 | * This should be equal to or greater than 0 and less than the the width in characters.
164 | * @param cursorX the distance from the left new text should be written to
165 | */
166 | public void setCursorX(int cursorX) {
167 | if (cursorX < 0 || cursorX >= widthInCharacters)
168 | throw new IllegalArgumentException("cursorX " + cursorX + " must be within range [0," + widthInCharacters + ")." );
169 |
170 | this.cursorX = cursorX;
171 | }
172 |
173 | /**
174 | * Gets the distance from the top new text will be written to.
175 | * @return
176 | */
177 | public int getCursorY() {
178 | return cursorY;
179 | }
180 |
181 | /**
182 | * Sets the distance from the top new text will be written to.
183 | * This should be equal to or greater than 0 and less than the the height in characters.
184 | * @param cursorY the distance from the top new text should be written to
185 | */
186 | public void setCursorY(int cursorY) {
187 | if (cursorY < 0 || cursorY >= heightInCharacters)
188 | throw new IllegalArgumentException("cursorY " + cursorY + " must be within range [0," + heightInCharacters + ")." );
189 |
190 | this.cursorY = cursorY;
191 | }
192 |
193 | /**
194 | * Sets the x and y position of where new text will be written to. The origin (0,0) is the upper left corner.
195 | * The x should be equal to or greater than 0 and less than the the width in characters.
196 | * The y should be equal to or greater than 0 and less than the the height in characters.
197 | * @param x the distance from the left new text should be written to
198 | * @param y the distance from the top new text should be written to
199 | */
200 | public void setCursorPosition(int x, int y) {
201 | setCursorX(x);
202 | setCursorY(y);
203 | }
204 |
205 | /**
206 | * Gets the default background color that is used when writing new text.
207 | * @return
208 | */
209 | public Color getDefaultBackgroundColor() {
210 | return defaultBackgroundColor;
211 | }
212 |
213 | /**
214 | * Sets the default background color that is used when writing new text.
215 | * @param defaultBackgroundColor
216 | */
217 | public void setDefaultBackgroundColor(Color defaultBackgroundColor) {
218 | if (defaultBackgroundColor == null)
219 | throw new NullPointerException("defaultBackgroundColor must not be null.");
220 |
221 | this.defaultBackgroundColor = defaultBackgroundColor;
222 | }
223 |
224 | /**
225 | * Gets the default foreground color that is used when writing new text.
226 | * @return
227 | */
228 | public Color getDefaultForegroundColor() {
229 | return defaultForegroundColor;
230 | }
231 |
232 | /**
233 | * Sets the default foreground color that is used when writing new text.
234 | * @param defaultForegroundColor
235 | */
236 | public void setDefaultForegroundColor(Color defaultForegroundColor) {
237 | if (defaultForegroundColor == null)
238 | throw new NullPointerException("defaultForegroundColor must not be null.");
239 |
240 | this.defaultForegroundColor = defaultForegroundColor;
241 | }
242 |
243 | /**
244 | * Gets the currently selected font
245 | * @return
246 | */
247 | public AsciiFont getAsciiFont() {
248 | return asciiFont;
249 | }
250 |
251 | /**
252 | * Sets the used font. It is advisable to make sure the parent component is properly sized after setting the font
253 | * as the panel dimensions will most likely change
254 | * @param font
255 | */
256 | public void setAsciiFont(AsciiFont font)
257 | {
258 | if(this.asciiFont == font)
259 | {
260 | return;
261 | }
262 | this.asciiFont = font;
263 |
264 | this.charHeight = font.getHeight();
265 | this.charWidth = font.getWidth();
266 | this.terminalFontFile = font.getFontFilename();
267 |
268 | Dimension panelSize = new Dimension(charWidth * widthInCharacters, charHeight * heightInCharacters);
269 | setPreferredSize(panelSize);
270 |
271 | glyphs = new BufferedImage[256];
272 |
273 | offscreenBuffer = new BufferedImage(panelSize.width, panelSize.height, BufferedImage.TYPE_INT_RGB);
274 | offscreenGraphics = offscreenBuffer.getGraphics();
275 |
276 | loadGlyphs();
277 |
278 | previousCharacters = new AsciiCharacterData[widthInCharacters][heightInCharacters];
279 | }
280 |
281 | /**
282 | * Gets the AsciiCharacterDataValues which are currently written
283 | * @return
284 | */
285 | public AsciiCharacterData[][] getCharacters() {
286 | return characters;
287 | }
288 |
289 | /**
290 | * Class constructor.
291 | * Default size is 80x24.
292 | */
293 | public AsciiPanel() {
294 | this(80, 24);
295 | }
296 |
297 | /**
298 | * Class constructor specifying the width and height in characters.
299 | * @param width
300 | * @param height
301 | */
302 | public AsciiPanel(int width, int height) {
303 | this(width, height, null);
304 | }
305 |
306 | /**
307 | * Class constructor specifying the width and height in characters and the AsciiFont
308 | * @param width
309 | * @param height
310 | * @param font if passing null, standard font CP437_9x16 will be used
311 | */
312 | public AsciiPanel(int width, int height, AsciiFont font) {
313 | super();
314 |
315 | if (width < 1) {
316 | throw new IllegalArgumentException("width " + width + " must be greater than 0." );
317 | }
318 |
319 | if (height < 1) {
320 | throw new IllegalArgumentException("height " + height + " must be greater than 0." );
321 | }
322 |
323 | widthInCharacters = width;
324 | heightInCharacters = height;
325 |
326 | defaultBackgroundColor = black;
327 | defaultForegroundColor = white;
328 |
329 | characters = new AsciiCharacterData[widthInCharacters][heightInCharacters];
330 |
331 | if(font == null) {
332 | font = AsciiFont.CP437_9x16;
333 | }
334 | setAsciiFont(font);
335 | clear();
336 | }
337 |
338 | @Override
339 | public void update(Graphics g) {
340 | paint(g);
341 | }
342 |
343 | @Override
344 | public void paint(Graphics g) {
345 | if (g == null)
346 | throw new NullPointerException();
347 |
348 | for (int x = 0; x < widthInCharacters; x++) {
349 | for (int y = 0; y < heightInCharacters; y++) {
350 | AsciiCharacterData previousCharacterData = previousCharacters[x][y];
351 | AsciiCharacterData newCharacterData = characters[x][y];
352 |
353 | if (previousCharacterData != null
354 | && newCharacterData.backgroundColor == previousCharacterData.backgroundColor
355 | && newCharacterData.foregroundColor == previousCharacterData.foregroundColor
356 | && newCharacterData.character == previousCharacterData.character)
357 | continue;
358 |
359 | LookupOp op = setColors(newCharacterData.backgroundColor, newCharacterData.foregroundColor);
360 | BufferedImage img = op.filter(glyphs[newCharacterData.character], null);
361 | offscreenGraphics.drawImage(img, x * charWidth, y * charHeight, null);
362 |
363 | previousCharacters[x][y] = newCharacterData;
364 | }
365 | }
366 |
367 | g.drawImage(offscreenBuffer,0,0,this);
368 | }
369 |
370 | private void loadGlyphs() {
371 | try {
372 | glyphSprite = ImageIO.read(AsciiPanel.class.getClassLoader().getResource(terminalFontFile));
373 | } catch (IOException e) {
374 | System.err.println("loadGlyphs(): " + e.getMessage());
375 | }
376 |
377 | for (int i = 0; i < 256; i++) {
378 | int sx = (i % 16) * charWidth;
379 | int sy = (i / 16) * charHeight;
380 |
381 | glyphs[i] = new BufferedImage(charWidth, charHeight, BufferedImage.TYPE_INT_ARGB);
382 | glyphs[i].getGraphics().drawImage(glyphSprite, 0, 0, charWidth, charHeight, sx, sy, sx + charWidth, sy + charHeight, null);
383 | }
384 | }
385 |
386 | /**
387 | * Create a LookupOp object (lookup table) mapping the original
388 | * pixels to the background and foreground colors, respectively.
389 | * @param bgColor the background color
390 | * @param fgColor the foreground color
391 | * @return the LookupOp object (lookup table)
392 | */
393 | private LookupOp setColors(Color bgColor, Color fgColor) {
394 | short[] a = new short[256];
395 | short[] r = new short[256];
396 | short[] g = new short[256];
397 | short[] b = new short[256];
398 |
399 | byte bga = (byte) (bgColor.getAlpha());
400 | byte bgr = (byte) (bgColor.getRed());
401 | byte bgg = (byte) (bgColor.getGreen());
402 | byte bgb = (byte) (bgColor.getBlue());
403 |
404 | byte fga = (byte) (fgColor.getAlpha());
405 | byte fgr = (byte) (fgColor.getRed());
406 | byte fgg = (byte) (fgColor.getGreen());
407 | byte fgb = (byte) (fgColor.getBlue());
408 |
409 | for (int i = 0; i < 256; i++) {
410 | if (i == 0) {
411 | a[i] = bga;
412 | r[i] = bgr;
413 | g[i] = bgg;
414 | b[i] = bgb;
415 | } else {
416 | a[i] = fga;
417 | r[i] = fgr;
418 | g[i] = fgg;
419 | b[i] = fgb;
420 | }
421 | }
422 |
423 | short[][] table = {r, g, b, a};
424 | return new LookupOp(new ShortLookupTable(0, table), null);
425 | }
426 |
427 | /**
428 | * Clear the entire screen to whatever the default background color is.
429 | * @return this for convenient chaining of method calls
430 | */
431 | public AsciiPanel clear() {
432 | return clear(' ', 0, 0, widthInCharacters, heightInCharacters, defaultForegroundColor, defaultBackgroundColor);
433 | }
434 |
435 | /**
436 | * Clear the entire screen with the specified character and whatever the default foreground and background colors are.
437 | * @param character the character to write
438 | * @return this for convenient chaining of method calls
439 | */
440 | public AsciiPanel clear(char character) {
441 | return clear(character, 0, 0, widthInCharacters, heightInCharacters, defaultForegroundColor, defaultBackgroundColor);
442 | }
443 |
444 | /**
445 | * Clear the entire screen with the specified character and whatever the specified foreground and background colors are.
446 | * @param character the character to write
447 | * @param foreground the foreground color or null to use the default
448 | * @param background the background color or null to use the default
449 | * @return this for convenient chaining of method calls
450 | */
451 | public AsciiPanel clear(char character, Color foreground, Color background) {
452 | return clear(character, 0, 0, widthInCharacters, heightInCharacters, foreground, background);
453 | }
454 |
455 | /**
456 | * Clear the section of the screen with the specified character and whatever the default foreground and background colors are.
457 | * The cursor position will not be modified.
458 | * @param character the character to write
459 | * @param x the distance from the left to begin writing from
460 | * @param y the distance from the top to begin writing from
461 | * @param width the height of the section to clear
462 | * @param height the width of the section to clear
463 | * @return this for convenient chaining of method calls
464 | */
465 | public AsciiPanel clear(char character, int x, int y, int width, int height) {
466 | return clear(new AsciiCharacterData(character, defaultForegroundColor, defaultBackgroundColor), x, y, width, height);
467 | }
468 |
469 | /**
470 | * Clear the section of the screen with the specified character and whatever the specified foreground and background colors are.
471 | * @param character the character to write
472 | * @param x the distance from the left to begin writing from
473 | * @param y the distance from the top to begin writing from
474 | * @param width the height of the section to clear
475 | * @param height the width of the section to clear
476 | * @param foreground the foreground color or null to use the default
477 | * @param background the background color or null to use the default
478 | * @return this for convenient chaining of method calls
479 | */
480 | public AsciiPanel clear(char character, int x, int y, int width, int height, Color foreground, Color background) {
481 | return clear(new AsciiCharacterData(character, foreground, background), x, y, width, height);
482 | }
483 |
484 | /**
485 | * Clear the section of the screen with the specified character and whatever the specified foreground and background colors are.
486 | * @param characterData the AsciiCharacterData to write
487 | * @param x the distance from the left to begin writing from
488 | * @param y the distance from the top to begin writing from
489 | * @param width the height of the section to clear
490 | * @param height the width of the section to clear
491 | * @return this for convenient chaining of method calls
492 | */
493 | public AsciiPanel clear(AsciiCharacterData characterData, int x, int y, int width, int height) {
494 | if (characterData.character < 0 || characterData.character >= glyphs.length)
495 | throw new IllegalArgumentException("character " + characterData.character + " must be within range [0," + glyphs.length + "]." );
496 |
497 | if (x < 0 || x >= widthInCharacters)
498 | throw new IllegalArgumentException("x " + x + " must be within range [0," + widthInCharacters + ")" );
499 |
500 | if (y < 0 || y >= heightInCharacters)
501 | throw new IllegalArgumentException("y " + y + " must be within range [0," + heightInCharacters + ")" );
502 |
503 | if (width < 1)
504 | throw new IllegalArgumentException("width " + width + " must be greater than 0." );
505 |
506 | if (height < 1)
507 | throw new IllegalArgumentException("height " + height + " must be greater than 0." );
508 |
509 | if (x + width > widthInCharacters)
510 | throw new IllegalArgumentException("x + width " + (x + width) + " must be less than " + (widthInCharacters + 1) + "." );
511 |
512 | if (y + height > heightInCharacters)
513 | throw new IllegalArgumentException("y + height " + (y + height) + " must be less than " + (heightInCharacters + 1) + "." );
514 |
515 | int originalCursorX = cursorX;
516 | int originalCursorY = cursorY;
517 | for (int xo = x; xo < x + width; xo++) {
518 | for (int yo = y; yo < y + height; yo++) {
519 | write(characterData, xo, yo);
520 | }
521 | }
522 | cursorX = originalCursorX;
523 | cursorY = originalCursorY;
524 |
525 | return this;
526 | }
527 |
528 | /**
529 | * Write a character to the cursor's position.
530 | * This updates the cursor's position.
531 | * @param character the character to write
532 | * @return this for convenient chaining of method calls
533 | */
534 | public AsciiPanel write(char character) {
535 | return write(character, cursorX, cursorY, defaultForegroundColor, defaultBackgroundColor);
536 | }
537 |
538 | /**
539 | * Write a character to the cursor's position with the specified foreground color.
540 | * This updates the cursor's position but not the default foreground color.
541 | * @param character the character to write
542 | * @param foreground the foreground color or null to use the default
543 | * @return this for convenient chaining of method calls
544 | */
545 | public AsciiPanel write(char character, Color foreground) {
546 | return write(character, cursorX, cursorY, foreground, defaultBackgroundColor);
547 | }
548 |
549 | /**
550 | * Write a character to the cursor's position with the specified foreground and background colors.
551 | * This updates the cursor's position but not the default foreground or background colors.
552 | * @param character the character to write
553 | * @param foreground the foreground color or null to use the default
554 | * @param background the background color or null to use the default
555 | * @return this for convenient chaining of method calls
556 | */
557 | public AsciiPanel write(char character, Color foreground, Color background) {
558 | return write(character, cursorX, cursorY, foreground, background);
559 | }
560 |
561 | /**
562 | * Write a character to the specified position.
563 | * This updates the cursor's position.
564 | * @param character the character to write
565 | * @param x the distance from the left to begin writing from
566 | * @param y the distance from the top to begin writing from
567 | * @return this for convenient chaining of method calls
568 | */
569 | public AsciiPanel write(char character, int x, int y) {
570 | return write(character, x, y, defaultForegroundColor, defaultBackgroundColor);
571 | }
572 |
573 | /**
574 | * Write a character to the specified position with the specified foreground color.
575 | * This updates the cursor's position but not the default foreground color.
576 | * @param character the character to write
577 | * @param x the distance from the left to begin writing from
578 | * @param y the distance from the top to begin writing from
579 | * @param foreground the foreground color or null to use the default
580 | * @return this for convenient chaining of method calls
581 | */
582 | public AsciiPanel write(char character, int x, int y, Color foreground) {
583 | return write(character, x, y, foreground, defaultBackgroundColor);
584 | }
585 |
586 | /**
587 | * Write a character to the specified position with the specified foreground and background colors.
588 | * This updates the cursor's position but not the default foreground or background colors.
589 | * @param character the character to write
590 | * @param x the distance from the left to begin writing from
591 | * @param y the distance from the top to begin writing from
592 | * @param foreground the foreground color or null to use the default
593 | * @param background the background color or null to use the default
594 | * @return this for convenient chaining of method calls
595 | */
596 | public AsciiPanel write(char character, int x, int y, Color foreground, Color background) {
597 | return write(new AsciiCharacterData(character, foreground, background), x, y);
598 | }
599 |
600 | /**
601 | * Write an AsciiCharacterData to the specified position.
602 | * This updates the cursor's position but not the default foreground or background colors.
603 | * @param characterData the AsciiCharacterData to write
604 | * @param x the distance from the left to begin writing from
605 | * @param y the distance from the top to begin writing from
606 | * @return this for convenient chaining of method calls
607 | */
608 | public AsciiPanel write(AsciiCharacterData characterData, int x, int y) {
609 | if (characterData.character < 0 || characterData.character >= glyphs.length)
610 | throw new IllegalArgumentException("character " + characterData.character + " must be within range [0," + glyphs.length + "]." );
611 |
612 | if (x < 0 || x >= widthInCharacters)
613 | throw new IllegalArgumentException("x " + x + " must be within range [0," + widthInCharacters + ")" );
614 |
615 | if (y < 0 || y >= heightInCharacters)
616 | throw new IllegalArgumentException("y " + y + " must be within range [0," + heightInCharacters + ")" );
617 |
618 | if (characterData.foregroundColor == null) {
619 | characterData.foregroundColor = defaultForegroundColor;
620 | }
621 |
622 | if (characterData.backgroundColor == null) {
623 | characterData.backgroundColor = defaultBackgroundColor;
624 | }
625 |
626 | characters[x][y] = characterData;
627 | cursorX = x + 1;
628 | cursorY = y;
629 | return this;
630 | }
631 |
632 | /**
633 | * Write a string to the cursor's position.
634 | * This updates the cursor's position.
635 | * @param string the string to write
636 | * @return this for convenient chaining of method calls
637 | */
638 | public AsciiPanel write(String string) {
639 | if (string == null)
640 | throw new NullPointerException("string must not be null" );
641 |
642 | if (cursorX + string.length() > widthInCharacters)
643 | throw new IllegalArgumentException("cursorX + string.length() " + (cursorX + string.length()) + " must be less than " + widthInCharacters + ".");
644 |
645 | return write(string, cursorX, cursorY, defaultForegroundColor, defaultBackgroundColor);
646 | }
647 |
648 | /**
649 | * Write a string to the cursor's position with the specified foreground color.
650 | * This updates the cursor's position but not the default foreground color.
651 | * @param string the string to write
652 | * @param foreground the foreground color or null to use the default
653 | * @return this for convenient chaining of method calls
654 | */
655 | public AsciiPanel write(String string, Color foreground) {
656 | if (string == null)
657 | throw new NullPointerException("string must not be null" );
658 |
659 | if (cursorX + string.length() > widthInCharacters)
660 | throw new IllegalArgumentException("cursorX + string.length() " + (cursorX + string.length()) + " must be less than " + widthInCharacters + "." );
661 |
662 | return write(string, cursorX, cursorY, foreground, defaultBackgroundColor);
663 | }
664 |
665 | /**
666 | * Write a string to the cursor's position with the specified foreground and background colors.
667 | * This updates the cursor's position but not the default foreground or background colors.
668 | * @param string the string to write
669 | * @param foreground the foreground color or null to use the default
670 | * @param background the background color or null to use the default
671 | * @return this for convenient chaining of method calls
672 | */
673 | public AsciiPanel write(String string, Color foreground, Color background) {
674 | if (string == null)
675 | throw new NullPointerException("string must not be null" );
676 |
677 | if (cursorX + string.length() > widthInCharacters)
678 | throw new IllegalArgumentException("cursorX + string.length() " + (cursorX + string.length()) + " must be less than " + widthInCharacters + "." );
679 |
680 | return write(string, cursorX, cursorY, foreground, background);
681 | }
682 |
683 | /**
684 | * Write a string to the specified position.
685 | * This updates the cursor's position.
686 | * @param string the string to write
687 | * @param x the distance from the left to begin writing from
688 | * @param y the distance from the top to begin writing from
689 | * @return this for convenient chaining of method calls
690 | */
691 | public AsciiPanel write(String string, int x, int y) {
692 | if (string == null)
693 | throw new NullPointerException("string must not be null" );
694 |
695 | if (x + string.length() > widthInCharacters)
696 | throw new IllegalArgumentException("x + string.length() " + (x + string.length()) + " must be less than " + widthInCharacters + "." );
697 |
698 | if (x < 0 || x >= widthInCharacters)
699 | throw new IllegalArgumentException("x " + x + " must be within range [0," + widthInCharacters + ")" );
700 |
701 | if (y < 0 || y >= heightInCharacters)
702 | throw new IllegalArgumentException("y " + y + " must be within range [0," + heightInCharacters + ")" );
703 |
704 | return write(string, x, y, defaultForegroundColor, defaultBackgroundColor);
705 | }
706 |
707 | /**
708 | * Write a string to the specified position with the specified foreground color.
709 | * This updates the cursor's position but not the default foreground color.
710 | * @param string the string to write
711 | * @param x the distance from the left to begin writing from
712 | * @param y the distance from the top to begin writing from
713 | * @param foreground the foreground color or null to use the default
714 | * @return this for convenient chaining of method calls
715 | */
716 | public AsciiPanel write(String string, int x, int y, Color foreground) {
717 | if (string == null)
718 | throw new NullPointerException("string must not be null" );
719 |
720 | if (x + string.length() > widthInCharacters)
721 | throw new IllegalArgumentException("x + string.length() " + (x + string.length()) + " must be less than " + widthInCharacters + "." );
722 |
723 | if (x < 0 || x >= widthInCharacters)
724 | throw new IllegalArgumentException("x " + x + " must be within range [0," + widthInCharacters + ")" );
725 |
726 | if (y < 0 || y >= heightInCharacters)
727 | throw new IllegalArgumentException("y " + y + " must be within range [0," + heightInCharacters + ")" );
728 |
729 | return write(string, x, y, foreground, defaultBackgroundColor);
730 | }
731 |
732 | /**
733 | * Write a string to the specified position with the specified foreground and background colors.
734 | * This updates the cursor's position but not the default foreground or background colors.
735 | * @param string the string to write
736 | * @param x the distance from the left to begin writing from
737 | * @param y the distance from the top to begin writing from
738 | * @param foreground the foreground color or null to use the default
739 | * @param background the background color or null to use the default
740 | * @return this for convenient chaining of method calls
741 | */
742 | public AsciiPanel write(String string, int x, int y, Color foreground, Color background) {
743 | if (string == null)
744 | throw new NullPointerException("string must not be null." );
745 |
746 | if (x + string.length() > widthInCharacters)
747 | throw new IllegalArgumentException("x + string.length() " + (x + string.length()) + " must be less than " + widthInCharacters + "." );
748 |
749 | if (x < 0 || x >= widthInCharacters)
750 | throw new IllegalArgumentException("x " + x + " must be within range [0," + widthInCharacters + ")." );
751 |
752 | if (y < 0 || y >= heightInCharacters)
753 | throw new IllegalArgumentException("y " + y + " must be within range [0," + heightInCharacters + ")." );
754 |
755 | if (foreground == null)
756 | foreground = defaultForegroundColor;
757 |
758 | if (background == null)
759 | background = defaultBackgroundColor;
760 |
761 | for (int i = 0; i < string.length(); i++) {
762 | write(string.charAt(i), x + i, y, foreground, background);
763 | }
764 | return this;
765 | }
766 |
767 | /**
768 | * Write a string to the center of the panel at the specified y position.
769 | * This updates the cursor's position.
770 | * @param string the string to write
771 | * @param y the distance from the top to begin writing from
772 | * @return this for convenient chaining of method calls
773 | */
774 | public AsciiPanel writeCenter(String string, int y) {
775 | if (string == null)
776 | throw new NullPointerException("string must not be null" );
777 |
778 | if (string.length() > widthInCharacters)
779 | throw new IllegalArgumentException("string.length() " + string.length() + " must be less than " + widthInCharacters + "." );
780 |
781 | int x = (widthInCharacters - string.length()) / 2;
782 |
783 | if (y < 0 || y >= heightInCharacters)
784 | throw new IllegalArgumentException("y " + y + " must be within range [0," + heightInCharacters + ")" );
785 |
786 | return write(string, x, y, defaultForegroundColor, defaultBackgroundColor);
787 | }
788 |
789 | /**
790 | * Write a string to the center of the panel at the specified y position with the specified foreground color.
791 | * This updates the cursor's position but not the default foreground color.
792 | * @param string the string to write
793 | * @param y the distance from the top to begin writing from
794 | * @param foreground the foreground color or null to use the default
795 | * @return this for convenient chaining of method calls
796 | */
797 | public AsciiPanel writeCenter(String string, int y, Color foreground) {
798 | if (string == null)
799 | throw new NullPointerException("string must not be null" );
800 |
801 | if (string.length() > widthInCharacters)
802 | throw new IllegalArgumentException("string.length() " + string.length() + " must be less than " + widthInCharacters + "." );
803 |
804 | int x = (widthInCharacters - string.length()) / 2;
805 |
806 | if (y < 0 || y >= heightInCharacters)
807 | throw new IllegalArgumentException("y " + y + " must be within range [0," + heightInCharacters + ")" );
808 |
809 | return write(string, x, y, foreground, defaultBackgroundColor);
810 | }
811 |
812 | /**
813 | * Write a string to the center of the panel at the specified y position with the specified foreground and background colors.
814 | * This updates the cursor's position but not the default foreground or background colors.
815 | * @param string the string to write
816 | * @param y the distance from the top to begin writing from
817 | * @param foreground the foreground color or null to use the default
818 | * @param background the background color or null to use the default
819 | * @return this for convenient chaining of method calls
820 | */
821 | public AsciiPanel writeCenter(String string, int y, Color foreground, Color background) {
822 | if (string == null)
823 | throw new NullPointerException("string must not be null." );
824 |
825 | if (string.length() > widthInCharacters)
826 | throw new IllegalArgumentException("string.length() " + string.length() + " must be less than " + widthInCharacters + "." );
827 |
828 | int x = (widthInCharacters - string.length()) / 2;
829 |
830 | if (y < 0 || y >= heightInCharacters)
831 | throw new IllegalArgumentException("y " + y + " must be within range [0," + heightInCharacters + ")." );
832 |
833 | if (foreground == null)
834 | foreground = defaultForegroundColor;
835 |
836 | if (background == null)
837 | background = defaultBackgroundColor;
838 |
839 | for (int i = 0; i < string.length(); i++) {
840 | write(string.charAt(i), x + i, y, foreground, background);
841 | }
842 | return this;
843 | }
844 |
845 | public void withEachTile(TileTransformer transformer){
846 | withEachTile(0, 0, widthInCharacters, heightInCharacters, transformer);
847 | }
848 |
849 | public void withEachTile(int left, int top, int width, int height, TileTransformer transformer){
850 | for (int x0 = 0; x0 < width; x0++) {
851 | for (int y0 = 0; y0 < height; y0++) {
852 | int x = left + x0;
853 | int y = top + y0;
854 |
855 | if (x < 0 || y < 0 || x >= widthInCharacters || y >= heightInCharacters)
856 | continue;
857 |
858 | transformer.transformTile(x, y, characters[x][y]);
859 | }
860 | }
861 | }
862 | }
863 |
--------------------------------------------------------------------------------