|
| 1 | +--- |
| 2 | +date: '2026-01-11T15:00:00+01:00' |
| 3 | +draft: false |
| 4 | +title: 'Terminal Graphics' |
| 5 | +weight: 22 |
| 6 | +--- |
| 7 | + |
| 8 | +The Graphics API provides primitives for drawing shapes, lines, and text at arbitrary positions in the terminal. It uses ANSI cursor addressing to place content at specific coordinates, with support for colors and the alternate screen buffer. |
| 9 | + |
| 10 | +## Graphics Interface |
| 11 | + |
| 12 | +```java |
| 13 | +public interface Graphics { |
| 14 | + void flush(); |
| 15 | + void clear(); |
| 16 | + void clearAndShowCursor(); |
| 17 | + |
| 18 | + TerminalColor getColor(); |
| 19 | + void setColor(TerminalColor color); |
| 20 | + |
| 21 | + TerminalTextStyle getTextStyle(); |
| 22 | + void setTextStyle(TerminalTextStyle textStyle); |
| 23 | + |
| 24 | + void drawRect(int x, int y, int width, int height); |
| 25 | + void fillRect(int x, int y, int width, int height); |
| 26 | + void drawLine(int x1, int y1, int x2, int y2); |
| 27 | + void drawCircle(int x, int y, int radius); |
| 28 | + void drawString(String str, int x, int y); |
| 29 | +} |
| 30 | +``` |
| 31 | + |
| 32 | +| Method | Description | |
| 33 | +|--------|-------------| |
| 34 | +| `drawRect(x, y, w, h)` | Draw a rectangle outline at (x, y) with the given width and height | |
| 35 | +| `fillRect(x, y, w, h)` | Fill a rectangle with the current background color | |
| 36 | +| `drawLine(x1, y1, x2, y2)` | Draw a line between two points | |
| 37 | +| `drawCircle(x, y, radius)` | Draw a circle centered at (x, y) | |
| 38 | +| `drawString(str, x, y)` | Draw text at position (x, y) | |
| 39 | +| `setColor(color)` | Set foreground and background colors for subsequent drawing | |
| 40 | +| `clear()` | Clear the entire screen | |
| 41 | +| `clearAndShowCursor()` | Clear the screen and restore the cursor | |
| 42 | +| `flush()` | Flush pending output to the terminal | |
| 43 | + |
| 44 | +Coordinates are column (x) and row (y), with (0, 0) at the top-left corner of the terminal. |
| 45 | + |
| 46 | +## Setup |
| 47 | + |
| 48 | +Create a `GraphicsConfiguration` from a terminal `Connection`, then obtain a `Graphics` instance: |
| 49 | + |
| 50 | +```java |
| 51 | +import org.aesh.graphics.AeshGraphicsConfiguration; |
| 52 | +import org.aesh.graphics.Graphics; |
| 53 | +import org.aesh.graphics.GraphicsConfiguration; |
| 54 | + |
| 55 | +GraphicsConfiguration gc = new AeshGraphicsConfiguration(connection); |
| 56 | +Graphics g = gc.getGraphics(); |
| 57 | +``` |
| 58 | + |
| 59 | +The `GraphicsConfiguration` also provides `getBounds()` to query the terminal size, which is useful for positioning elements relative to the terminal dimensions. |
| 60 | + |
| 61 | +## Example Command |
| 62 | + |
| 63 | +```java |
| 64 | +@CommandDefinition(name = "draw", description = "Draw shapes") |
| 65 | +public class DrawCommand implements Command<CommandInvocation> { |
| 66 | + |
| 67 | + private final GraphicsConfiguration gc; |
| 68 | + |
| 69 | + public DrawCommand(Connection connection) { |
| 70 | + this.gc = new AeshGraphicsConfiguration(connection); |
| 71 | + } |
| 72 | + |
| 73 | + @Override |
| 74 | + public CommandResult execute(CommandInvocation invocation) { |
| 75 | + // Switch to alternate buffer to preserve scroll history |
| 76 | + invocation.getShell().enableAlternateBuffer(); |
| 77 | + |
| 78 | + Graphics g = gc.getGraphics(); |
| 79 | + |
| 80 | + // Blue rectangle |
| 81 | + g.setColor(new TerminalColor(Color.BLUE, Color.DEFAULT)); |
| 82 | + g.drawRect(5, 2, 30, 8); |
| 83 | + g.flush(); |
| 84 | + |
| 85 | + // Red filled area |
| 86 | + g.setColor(new TerminalColor(Color.DEFAULT, Color.RED)); |
| 87 | + g.fillRect(40, 3, 15, 6); |
| 88 | + g.flush(); |
| 89 | + |
| 90 | + // Cyan text |
| 91 | + g.setColor(new TerminalColor(Color.CYAN, Color.DEFAULT)); |
| 92 | + g.drawString("Hello from Aesh Graphics!", 10, 12); |
| 93 | + g.flush(); |
| 94 | + |
| 95 | + // Green circle |
| 96 | + g.setColor(new TerminalColor(Color.GREEN, Color.DEFAULT)); |
| 97 | + g.drawCircle(60, 8, 5); |
| 98 | + g.flush(); |
| 99 | + |
| 100 | + // Wait for 'q' to exit |
| 101 | + try { |
| 102 | + while (!invocation.input().equals(Key.q)) { |
| 103 | + // wait |
| 104 | + } |
| 105 | + } catch (InterruptedException ignored) { |
| 106 | + } |
| 107 | + |
| 108 | + // Restore terminal |
| 109 | + g.clearAndShowCursor(); |
| 110 | + invocation.getShell().enableMainBuffer(); |
| 111 | + return CommandResult.SUCCESS; |
| 112 | + } |
| 113 | +} |
| 114 | +``` |
| 115 | + |
| 116 | +Register the command with the terminal connection: |
| 117 | + |
| 118 | +```java |
| 119 | +TerminalConnection connection = new TerminalConnection( |
| 120 | + Charset.defaultCharset(), System.in, System.out, null); |
| 121 | + |
| 122 | +CommandRegistry registry = AeshCommandRegistryBuilder.builder() |
| 123 | + .command(new DrawCommand(connection)) |
| 124 | + .create(); |
| 125 | +``` |
| 126 | + |
| 127 | +## Colors |
| 128 | + |
| 129 | +Use `TerminalColor` to set foreground and background colors: |
| 130 | + |
| 131 | +```java |
| 132 | +import org.aesh.terminal.formatting.Color; |
| 133 | +import org.aesh.terminal.formatting.TerminalColor; |
| 134 | + |
| 135 | +// Foreground only |
| 136 | +g.setColor(new TerminalColor(Color.RED, Color.DEFAULT)); |
| 137 | + |
| 138 | +// Both foreground and background |
| 139 | +g.setColor(new TerminalColor(Color.WHITE, Color.BLUE)); |
| 140 | +``` |
| 141 | + |
| 142 | +Available colors: `BLACK`, `RED`, `GREEN`, `YELLOW`, `BLUE`, `MAGENTA`, `CYAN`, `WHITE`, `DEFAULT`. |
| 143 | + |
| 144 | +Color changes apply to all subsequent drawing operations until `setColor()` is called again. |
| 145 | + |
| 146 | +## Alternate Screen Buffer |
| 147 | + |
| 148 | +For full-screen graphics, use the alternate screen buffer. This preserves the user's terminal history and restores it when your command finishes: |
| 149 | + |
| 150 | +```java |
| 151 | +// Enter alternate buffer |
| 152 | +invocation.getShell().enableAlternateBuffer(); |
| 153 | + |
| 154 | +// ... draw graphics ... |
| 155 | + |
| 156 | +// Return to main buffer (restores previous content) |
| 157 | +invocation.getShell().enableMainBuffer(); |
| 158 | +``` |
| 159 | + |
| 160 | +## Animation |
| 161 | + |
| 162 | +Combine `clear()`, drawing, `flush()`, and `Thread.sleep()` for simple animations: |
| 163 | + |
| 164 | +```java |
| 165 | +g.setColor(new TerminalColor(Color.DEFAULT, Color.GREEN)); |
| 166 | +for (int x = 0; x < 80; x++) { |
| 167 | + g.clear(); |
| 168 | + g.fillRect(x, 10, 10, 5); |
| 169 | + g.flush(); |
| 170 | + Thread.sleep(50); |
| 171 | +} |
| 172 | +``` |
| 173 | + |
| 174 | +## Bounds Checking |
| 175 | + |
| 176 | +The graphics implementation clips drawing to the terminal bounds. Use `GraphicsConfiguration.getBounds()` to adapt your layout to the terminal size: |
| 177 | + |
| 178 | +```java |
| 179 | +Size bounds = gc.getBounds(); |
| 180 | +int centerX = bounds.getWidth() / 2; |
| 181 | +int centerY = bounds.getHeight() / 2; |
| 182 | +g.drawString("Centered", centerX - 4, centerY); |
| 183 | +``` |
0 commit comments