## The ScreenBuffer A *screenBuffer* is a buffer holding contents for a rectangular area. Each cell of the rectangular area contains: * a character * a 8-bit foreground color * a 8-bit background color * a style (bit flags: bold, dim, italic, underline, blink, inverse, hidden, strike) * a blending mask (bit flags: foreground transparency, background transparency, character transparency and style transparency) They are two kinds of *screenBuffers*, depending on the write-destination: * *screenBuffer* writing directly to the terminal * *screenBuffer* writing to another *screenBuffer* When there are a lot of moving things, it is a good practice to first create one big *screenBuffer* mapping the whole terminal, then create smaller *screenBuffers* writing to the terminal's *screenBuffer*, each one managing a part of the UI of the application, a widget, a moving area, a sprite, etc. ScreenBuffer's write to the terminal are optimized ([if the *delta* option is on](#ref.ScreenBuffer.draw)): since writing to a terminal can be CPU-intensive, only cells that have changed are written, avoiding to refresh the whole screen for no reason. In that case, the *screenBuffer* will always try to minimize the amount of terminal escape sequences to produce the new *frame*. ## Table of Contents * Constructor and static methods: * [ScreenBuffer()](#ref.ScreenBuffer.new) * [ScreenBuffer.create()](#ref.ScreenBuffer.create) * [ScreenBuffer.createFromString()](#ref.ScreenBuffer.createFromString) * [ScreenBuffer.loadImage()](#ref.ScreenBuffer.loadImage) * [ScreenBuffer.attr2object()](#ref.ScreenBuffer.attr2object) * [ScreenBuffer.object2attr()](#ref.ScreenBuffer.object2attr) * [ScreenBuffer.loadSync()](#ref.ScreenBuffer.loadSync) * Properties: * [.dst](#ref.ScreenBuffer.dst) * [.x](#ref.ScreenBuffer.xy) * [.y](#ref.ScreenBuffer.xy) * [.blending](#ref.ScreenBuffer.blending) * Methods: * [.fill()](#ref.ScreenBuffer.fill) * [.clear()](#ref.ScreenBuffer.clear) * [.put()](#ref.ScreenBuffer.put) * [.get()](#ref.ScreenBuffer.get) * [.resize()](#ref.ScreenBuffer.resize) * [.draw()](#ref.ScreenBuffer.draw) * [.drawCursor()](#ref.ScreenBuffer.drawCursor) * [.moveTo()](#ref.ScreenBuffer.moveTo) * [.vScroll()](#ref.ScreenBuffer.vScroll) * [.dumpChars()](#ref.ScreenBuffer.dumpChars) * [.dump()](#ref.ScreenBuffer.dump) * [.saveSync()](#ref.ScreenBuffer.saveSync) * [The Attribute Object](#ref.ScreenBuffer.attributes) ### new ScreenBuffer( options ) * options `Object`, where: * width `integer` buffer width (default: dst.width) * height `integer` buffer height (default: dst.height) * dst: `Terminal` or `ScreenBuffer` instance, the destination to write on * x `integer` (optional) default x-position in the dst * y `integer` (optional) default y-position in the dst * blending `boolean` (optional, default: false) default value for [.draw()](#ref.ScreenBuffer.draw)'s blending option, if true, blending is enabled (e.g. background transparency, char transparency, etc...) * wrap `boolean` (optional, default: false) default wrapping behavior of [.put()](#ref.ScreenBuffer.put) * noFill `boolean` (optional, default: false) if true, the *screenBuffer* will not be filled with empty chars, i.e. it will not call [.fill()](#ref.ScreenBuffer.fill), useful for performance to avoid useless reset This creates a ScreenBuffer instance with the appropriate options. ### ScreenBuffer.create( options ) DEPRECATED, use [new ScreenBuffer()](#ref.ScreenBuffer.new) instead. ### ScreenBuffer.createFromString( options , str ) * options `Object`, where: * attr `Object` or `integer` attributes of the chars (attribute object or bit flags, see: [the attribute object](#ref.ScreenBuffer.attributes)) * transparencyChar `string` (optional) a single character that will have get the transparency attribute * transparencyType `integer` (optional, default: full transparency) bit flags for the transparency char * str `string` the source string This creates a ScreenBuffer instance from a string. The height and width of the *screenBuffer* is computed using respectively the number of lines and the length of the largest line. The string is written into the *screenBuffer* using the `attr` option. See [the attr object and flags](#ref.ScreenBuffer.attributes) for details. If the `transparencyChar` option is set, this character will produce a transparent cell, or if `transparencyType` is specified, a partly transparent cell. See [the transparency flags](#ref.ScreenBuffer.attributes) for details. ### ScreenBuffer.loadImage( url , [options] , callback ) * url `string` the file path or URL of the image * options `object` (optional), where: * term `Terminal` (optional, default to `termkit.terminal`) pass a *Terminal* instance, so the correct palette will be known when converting the *True Color* image into a 8-bit ScreenBuffer * shrink `object` (optional, but **recommanded**) if set, the image may be shrinked to conform to the max width and height. When shrinking, aspect ratio is always preserved. It has those properties: * width `integer` the max width of the image * height `integer` the max height of the image * callback `Function( error , image )` the callback, where: * error: truthy if an error occured * image `ScreenBufferHD` the *screenBuffer* of the image This creates a ScreenBufferHD from an image. Support all format supported by [get-pixels](#https://www.npmjs.com/package/get-pixels), namely *PNG*, *JPEG* and *GIF*. Only the first frame of *GIF* are used ATM. It uses the *upper half block* UTF-8 character (▀) to double the height resolution and produces the correct aspect ratio: the upper half having a foreground color and the lower half having the background color. The *shrink* object option can be used to reduce the size of the image. It is suggested to set it to `{ width: term.width, height: term.height * 2 }` to avoid creating a 2000 lines image. The *alpha channel* is correctly supported, also it is important to draw that image to another *screenBufferHD* for this to work as expected (remember: blending only works when drawing on another *screenBufferHD*). Moreover, the target buffer must have **consistent foreground and background color**, since all the area will be filled with `▀` characters. Something like that will do the trick: ```js var screen = new ScreenBuffer( { dst: term , noFill: true } ) ; screen.fill( attr: { // Both foreground and background must have the same color color: 0 , bgColor: 0 } } ) ; ScreenBuffer.loadImage( path_to_image , { terminal: term , shrink: { width: term.width , height: term.height * 2 } } , function( error , image ) { if ( error ) { throw error ; } // Doh! image.draw( { dst: screen , blending: true } ) ; screen.draw() ; } ) ; ``` There is a full example of an image viewer located here: `./sample/image-viewer.js` in the repository. ### ScreenBuffer.attr2object( attrFlags ) / .attr2object( attrFlags ) * attrFlags `integer` attributes in the bit flags form It returns the object form of the attributes from its bit flags form. It exists both as a static method and as an instance method. ### ScreenBuffer.object2attr( attrObject ) / .object2attr( attrObject ) * attrObject `Object` attributes in the object form It returns the bit flags form of the attributes from its object form. It exists both as a static method and as an instance method. ### ScreenBuffer.loadSync( filepath ) * filepath `string` the path of a *screenBuffer* file to load This static method loads **synchronously** a *screenBuffer* file and returns a `ScreenBuffer` instance. ### .dst This property contains a `Terminal` or `ScreenBuffer` instance, that is the destination to write on. ### .x , .y Those properties are respectively the x and the y coordinate, in the *dst* (destination), where the *screenBuffer* should be drawn. This can be overriden when invoking [*.draw()*](#ref.ScreenBuffer.draw). ### .blending A `boolean`, the is default value for [*.draw()*](#ref.ScreenBuffer.draw)'s blending option. If true, blending is enabled (e.g. background transparency, char transparency, etc). ### .fill( [options] ) * options `Object` (optional), where: * attr `Object` or `integer` (optional) attributes of the chars (attribute object or bit flags, see: [the attribute object](#ref.ScreenBuffer.attributes)) (default to the default attributes) * char `string` (optional) a single character used to fill the buffer (default: the space character) * region: `Object` or `Rect` (optional), a [`Rect` compliant object](Rect.md#ref.Rect.new) defining the region to fill (default: fill the whole ScreenBuffer) It fills the *screenBuffer* with the specified *char* and *attributes*. If the *region* is specified, then only that *region* will be filled. ### .clear() It clears the *screenBuffer*, this is like calling [.fill()](#ref.ScreenBuffer.fill) with no argument. ### .put( options , text ) or .put( options , format , [arg1] , [arg2] , ... ) * options `Object`, where: * x `integer` (optional) x-coordinate where to put the text, bypassing the cursor x-coordinate * y `integer` (optional) y-coordinate where to put the text, bypassing the cursor y-coordinate * markup `boolean` or 'ansi' (optional) true if the text contains markup that should be interpreted, 'ansi' if it contains *ANSI* code * attr `Object` or `integer` (optional) attributes of the chars (attribute object or bit flags, see: [the attribute object](#ref.ScreenBuffer.attributes)) * wrap `boolean` (optional) if true, text wrapping is enabled: when the cursor move beyond the last column, it is moved to the begining of the next line * newLine: `boolean` (optional) if true, then \r and \n produce new lines, false by default: .put() does not manage lines * clip: `object` (optional) if set, it defines the clipping area, nothing is written outside of it, and if the 'wrap' option is set, wrapping is done on its boundary. Properties: * x * y * width * height * clipChar: `string` (optional) a single char used when the text will be clipped, e.g.: '…' * direction `string` (optional) the direction where the cursor move after each char, one of: * 'right' (default) * 'left' * 'up' * 'down' * 'none'/null: do not move after puting a char * dx `integer` (optional) x-coordinate increment of the cursor after each character (default: 1), allow more precise controle than the *direction* option * dy `integer` (optional) y-coordinate increment after each character (default: 0), allow more precise controle than the *direction* option * text `string` the string to put into the *screenBuffer* * format `string` the formated string to put into the *screenBuffer* (works just like any other `term( format , args... )`) * arg1 (optional) the first argument of the format * arg2... * ... It puts some text into the *screenBuffer*, using the provided *attributes*. For the *markup* option, see also [the full style markup reference](markup.md#top). ### .get( [options] ) * options `Object` (optional), where: * x `integer` (optional) x-coordinate of the cell to get, bypassing the cursor x-coordinate * y `integer` (optional) y-coordinate of the cell to get, bypassing the cursor y-coordinate It gets the character and attributes of the cell the *screenBuffer*'s cursor is at, or the cell for the supplied x and y coordinate. It returns an object, where: * char `string` a single character string, the character at that cell * attr `Object` the attribute object for this cell, see: [the attribute object](#ref.ScreenBuffer.attributes) ### .resize( fromRect ) * fromRect `Object` or `Rect` the rectangle used to resize the buffer, if it is an object, it should contains properties needed by the [`Rect`'s contructor](Rect.md#ref.Rect.new), namely either: * width `integer` the width of the rectangle * height `integer` the height of the rectangle * x `integer` (optional, default to the left-most x-coordinate) the minimum x-coordinate of the rectangle * y `integer` (optional, default to the top-most y-coordinate) the minimum y-coordinate of the rectangle or: * xmin `integer` the minimum x-coordinate of the rectangle * xmax `integer` the maximum x-coordinate of the rectangle (included) * ymin `integer` the minimum y-coordinate of the rectangle * ymax `integer` the maximum y-coordinate of the rectangle (included) This resizes the *screenBuffer*. If only the *width* and the *height* is given, the *screenBuffer* will shrink/enlarge from its right-side and bottom-side. With the four properties, it is possible to define where the current *screenBuffer* content will land after the resize. ### .draw( [options] ) * options `Object` (optional) if provided, each defined option will override the default behavior. Available options are: * dst `Terminal` or `ScreenBuffer` (optional) override `screenBuffer.dst` * x `integer` (optional) override `screenBuffer.x` * y `integer` (optional) override `screenBuffer.y` * srcClipRect `Rect` (optional, default: the whole source region is used) the source clipping rectangle * dstClipRect `Rect` (optional, default: the whole destination region is used) the destination clipping rectangle * blending `boolean` (optional, default: false) if true blending (transparencies) is allowed, also **if dst is a terminal, partial transparency does not work** * delta `boolean` (optional, default: false) if true and if the destination is a **terminal**, only the cells that have changed since the last draw will be updated: **it will keep performance of terminal application high** * wrap `boolean` or `string` (optional, default: false) if set, wrapping will be enabled, it can be set to: * 'x': only wrap along the x-axis * 'y': only wrap along the y-axis * true, 'both': wrap along the x and y axis * false: no wrapping * tile `boolean` (optional, default: false) if true, the source will fill the destination entirely using tiling: the source is repeated multiple times along the x and y axis. This draws the current *screenBuffer* into its *dst* (destination), which is either a `Terminal` or another `ScreenBuffer` instance. Blending works only when drawing to another *screenBuffer*. ### .drawCursor( [options] ) * options `Object` (optional) if provided, each defined option will override the default behavior. Available options are: * dst `Terminal` or `ScreenBuffer` (optional) override `screenBuffer.dst` This draws the current *screenBuffer*'s cursor into its *dst* (destination), which is either a `Terminal` or another `ScreenBuffer` instance. *Drawing the cursor* means that the destination's cursor is moved to the coordinate of the source's cursor. This method is useful if the *screenBuffer* is (for example) a widget that receive user input: the user must know where he is typing. ### .moveTo( x , y ) * x `integer` new cursor x-coordinate * y `integer` new cursor y-coordinate It moves the *screenBuffer*'s cursor. ### .vScroll( lineOffset , [attr] , [ymin] , [ymax] , [scrollTerminal] ) *or* .vScroll( offset , [scrollTerminal] ) * lineOffset `integer` the vertical offset (the number of lines), positive values move the content toward crescent *y* coordinates, thus move the content down, negative values move the content up. * attr `Object` or `integer` attributes of inserted empty lines (attribute object or bit flags, see: [the attribute object](#ref.ScreenBuffer.attributes)) * scrollTerminal `boolean` (optional, default: false) if true **AND** if the *screenBuffer*'s *dst* is a *Terminal* instance, it will scroll the underlying terminal, see details below. This scrolls the *screenBuffer*'s content vertically. If *scrollTerminal* option is set **AND** if the *screenBuffer*'s *dst* is a *Terminal* instance, then the following happens: * the *dst terminal* is issued a *.scrollingRegion()* with the *screenBuffer* vertical bounds * the *dst terminal* is issued a *.scrollDown()* or a *.scrollUp()* depending on the lineOffset sign * the internal buffer storing last draw's data is updated, so the next call to *.draw()* with the *delta* option on will not redraw the region that has scrolled unless it has changed again * the *dst terminal* is issued a .resetScrollingRegion() This option has **one big limitation:** the *screenBuffer* should cover the whole terminal's width, because terminals only supports full-width scrolling region. You *may* avoid using this option for thinner *screenBuffers*, because things lying to the left or to the right would be scrolled too. Also note that it doesn't *draw* the *screenBuffer* to the terminal, but it the internal delta is maintained properly. ### .dumpChars() Returns a string containing a dump of the *screenBuffer*'s characters. Mostly useful for debugging purpose. ### .dump() Returns a string containing a dump of the *screenBuffer*, including attributes. Mostly useful for debugging purpose, but will likely gives you a headache. ### .saveSync( filepath ) * filepath `string` the path of the file to write the *screenBuffer* This saves **synchronously** the *screenBuffer* to a file. ### The Attributes Object An attributes object contains attributes to style cells. Available attributes are: * color `integer` or `string` the foreground color index (ranging from 0 to 255) or the color name * defaultColor `boolean` if true, set the foreground color to the default terminal foreground color * bgColor `integer` or `string` the background color index (ranging from 0 to 255) or the color name * bgDefaultColor `boolean` if true, set the background color to the default terminal background color * bold `boolean` * dim `boolean` * italic `boolean` * underline `boolean` * blink `boolean` (note: most terminal does not support it) * inverse `boolean` * hidden `boolean` * strike `boolean` * transparency `boolean` if true, all transparencies are activated * fgTransparency `boolean` *foreground color transparency*, anything drawn with that attribute will use the existing destination's foreground color instead of its own foreground color * bgTransparency `boolean` *background color transparency*, anything drawn with that attribute will use the existing destination's background color instead of its own background color * styleTransparency `boolean` *style transparency*, anything drawn with that attribute will use the existing destination's style instead of its own style. Styles cover the bold, dim, italic, underline, blink, inverse, hidden and strike attributes. * charTransparency `boolean` *character transparency*, anything drawn with that attribute will use the existing destination's character instead of its own character Transparency can achieve some special FX, like making a colorful rectangle moving behind some text.