1 // Copyright 2022 Garrett D'Amore 2 // 3 // Distributed under the Boost Software License, Version 1.0. 4 // (See accompanying file LICENSE or https://www.boost.org/LICENSE_1_0.txt) 5 6 module dcell.screen; 7 8 import core.time; 9 import std.concurrency; 10 11 public import dcell.cell; 12 public import dcell.cursor; 13 public import dcell.key; 14 public import dcell.event; 15 public import dcell.mouse; 16 17 interface Screen 18 { 19 /** 20 * Clears the screen. This doesn't take effect until 21 * the show function is called. 22 */ 23 void clear(); 24 25 /** 26 * Retrive the contents for a given address. This is taken from 27 * the backing draw buffer, and won't necessarily reflect what is 28 * displayed to the user until show is called. 29 */ 30 ref Cell opIndex(size_t x, size_t y); 31 32 /** Convenience for indexing */ 33 final ref Cell opIndex(Coord pos) 34 { 35 return this[pos.x, pos.y]; 36 } 37 38 /** 39 * Set the content for for a given location. This won't necessarily 40 * take effect until the show function is called. 41 */ 42 void opIndexAssign(Cell, size_t x, size_t y); 43 44 45 /** Convenience for indexing. */ 46 final void opIndexAssign(Cell c, Coord pos) 47 { 48 this[pos.x, pos.y] = c; 49 } 50 51 /** Support $ operation in indices. */ 52 size_t opDollar(size_t dim)() { 53 static if (dim == 0) { 54 return size().x; 55 } else { 56 return size().y; 57 } 58 } 59 60 /** 61 * Show the cursor at its current location. 62 */ 63 void showCursor(Cursor); 64 65 /** 66 * Move the cursor to the given location, and show 67 * it using the appropriate style. 68 * 69 * Params: 70 * pos = position of the cursor 71 * cur = cursor style 72 */ 73 void showCursor(Coord pos, Cursor cur = Cursor.current); 74 75 /** 76 * It would be nice to know if a given key is supported by 77 * a terminal. Note that this is best-effort, and some terminals 78 * may present the ability to support a key, without actually having 79 * such a physical key and some combinations may be suppressed by 80 * the emulator or the environment the emulator runs in. 81 * 82 * Returns: true if the key appears to be supported on the terminal. 83 */ 84 bool hasKey(Key); 85 86 /** 87 * Obtain the terminal window size. 88 * The x, y represent the number of columns and rows. 89 * The highest valid address will be coord.x-1, coord.y-1. 90 * 91 * Returns: terminal dimensions 92 */ 93 Coord size(); 94 95 /** 96 * If start was called without a Tid to send to, then events 97 * are delivered into a queue that can be polled via this API. 98 * This function is thread safe. 99 * Params: 100 * dur = maximum time to wait, if no event is available then EventType.none is returned. 101 * Returns: 102 * The event, which will be EventType.none if it times out, or EventType.closed if it is stopped. 103 */ 104 Event receiveEvent(Duration dur); 105 106 /** 107 * Receive events, withotu a timeout. This only works if start 108 * was called without a tid. 109 */ 110 Event receiveEvent(); 111 112 /** 113 * Enable backeted paste mode mode. Bracketed paste mode 114 * will pasted content in a single event, and is therefore 115 * distinguishable from individually typed characters. 116 * 117 * Params: 118 * b = true to enable bracketed paste, false for disable 119 */ 120 void enablePaste(bool b); 121 122 /** 123 * Do we have a mouse? This may be overly optimitistic for some 124 * terminals, but it is a good first guess. 125 * 126 * Returns: true if the terminal is thought to support mouse events 127 */ 128 bool hasMouse(); 129 130 /** 131 * Enable mouse mode. This can cause terminals/emulators 132 * to behave differently -- for example affecting the ability 133 * to scroll or use copy/paste. 134 * 135 * Params: 136 * en = mouse events to report (mask) 137 */ 138 void enableMouse(MouseEnable en); 139 140 /** 141 * Enable typical mouse features. This enables tracking, but 142 * leaves drag events disabled. Enabling mouse drag will impair 143 * use of copy-paste at the OS level, which many users tend to 144 * find frustrating. 145 */ 146 final void enableMouse() 147 { 148 enableMouse(MouseEnable.buttons | MouseEnable.motion); 149 } 150 151 /** 152 * Disable all mouse handling/capture. 153 */ 154 final void disableMouse() 155 { 156 enableMouse(MouseEnable.disable); 157 } 158 159 /** 160 * If the terminal supports color, this returns the 161 * the number of colors. 162 * 163 * Returns: the number of colors supported (max 256), or 0 if monochrome 164 */ 165 int colors(); 166 167 /** 168 * Show content on the screen, doing so efficiently. 169 */ 170 void show(); 171 172 /** 173 * Update the screen, writing every cell. This should be done 174 * to repair screen damage, for example. 175 */ 176 void sync(); 177 178 /** 179 * Emit a beep or bell. This is done immediately. 180 */ 181 void beep(); 182 183 /** 184 * Attempt to resize the terminal. YMMV. 185 */ 186 void setSize(Coord); 187 188 /** 189 * Set the default style used when clearning the screen, etc. 190 */ 191 void setStyle(Style); 192 193 /** 194 * Fill the entire screen with the given content and style. 195 * Content is not drawn until the show() or sync() functions are called. 196 */ 197 void fill(string s, Style style); 198 199 /** 200 * Fill the entire screen with the given content, but preserve the style. 201 */ 202 void fill(string s); 203 204 /** 205 * Applications should call this in response to receiving 206 * a resize event. (This can't be done automatically to 207 * avoid thread safety issues.) 208 */ 209 void resize(); 210 211 /** 212 * Start should be called to start processing. Once this begins, 213 * events (see event.d) will be delivered to the caller via 214 * std.concurrency.send(). Additioanlly, this may change terminal 215 * settings to put the input stream into raw mode, etc. 216 */ 217 void start(); 218 void start(Tid); 219 220 /** 221 * Stop is called to stop processing on teh screen. The terminal 222 * settings will be restored, and the screen may be cleared. Input 223 * events will no longer be delivered. This should be called when 224 * the program is exited, or if suspending (to run a subshell process 225 * interactively for example). 226 */ 227 void stop(); 228 }