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