class Crysterm::Screen

Overview

Represents a screen.

Included Modules

Defined in:

screen.cr
screen_angles.cr
screen_attributes.cr
screen_children.cr
screen_cursor.cr
screen_decoration.cr
screen_drawing.cr
screen_focus.cr
screen_interaction.cr
screen_rendering.cr
screen_resize.cr
screen_rows.cr
screen_screenshot.cr

Constant Summary

ANGLE_TABLE = {0 => ' ', 1 => '│', 2 => '─', 3 => '┌', 4 => '│', 5 => '│', 6 => '└', 7 => '├', 8 => '─', 9 => '┐', 10 => '─', 11 => '┬', 12 => '┘', 13 => '┤', 14 => '┴', 15 => '┼'}

Every ACS angle character can be represented by 4 bits ordered like this: [langle][uangle][rangle][dangle]

ANGLES = {'┘', '┐', '┌', '└', '┼', '├', '┤', '┴', '┬', '│', '─'}

All angles, uniq list

BITWISE_D_ANGLE = 1 << 0
BITWISE_L_ANGLE = 1 << 3
BITWISE_R_ANGLE = 1 << 1
BITWISE_U_ANGLE = 1 << 2
D_ANGLES = {'┘', '└', '┼', '├', '┤', '┴', '│'}
DEFAULT_ATTR = ((0 << 18) | (511 << 9)) | 511
DEFAULT_CHAR = ' '
L_ANGLES = {'┌', '└', '┼', '├', '┴', '┬', '─'}

Left, top, right, and bottom angles

R_ANGLES = {'┘', '┐', '┼', '┤', '┴', '┬', '─'}
U_ANGLES = {'┐', '┌', '┼', '├', '┤', '┬', '│'}

Constructors

Class Method Summary

Instance Method Summary

Instance methods inherited from module Crysterm::Mixin::Instances

bind bind, destroy destroy

Instance methods inherited from module Crysterm::Mixin::Children

<<(widget : Widget) <<, >>(widget : Widget) >>, append(element)
append(*elements)
append
, children children, collect_ancestors(el : Widget) : Array(Widget) collect_ancestors, collect_descendants(el : Widget) : Array(Widget) collect_descendants, each_ancestor(&block : Proc(Widget, Nil)) : Nil each_ancestor, each_descendant(&block : Proc(Widget, Nil)) : Nil each_descendant, emit_ancestors(ev : EventHandler::Event | EventHandler::Event.class) : Nil emit_ancestors, emit_descendants(ev : EventHandler::Event | EventHandler::Event.class) : Nil emit_descendants, has_ancestor?(obj) has_ancestor?, has_descendant?(obj) has_descendant?, insert(element, i = -1) insert, insert_after(element, other) insert_after, insert_before(element, other) insert_before, prepend(element) prepend, remove(element) remove, self_and_each_ancestor(&block : Proc(Widget, Nil)) : Nil self_and_each_ancestor, self_and_each_descendant(&block : Proc(Widget, Nil)) : Nil self_and_each_descendant

Instance methods inherited from module Crysterm::Mixin::Pos

abottom : Int32 | Nil abottom, abottom=(abottom : Int32 | Nil) abottom=, aleft : Int32 | Nil aleft, aleft=(aleft : Int32 | Nil) aleft=, aright : Int32 | Nil aright, aright=(aright : Int32 | Nil) aright=, atop : Int32 | Nil atop, atop=(atop : Int32 | Nil) atop=, lpos : LPos | Nil lpos, lpos=(lpos : LPos | Nil) lpos=, renders renders, renders=(renders) renders=, scrollable=(scrollable) scrollable=, scrollable? scrollable?

Instance methods inherited from module Crysterm::Mixin::Name

name : String | Nil name, name=(name : String | Nil) name=

Macros inherited from module Crysterm::Macros

alias_method(new_method, old_method) alias_method, alias_previous(*new_methods) alias_previous, handle(event, handler = nil) handle

Constructor Detail

def self.new(input : IO = @input, output : IO = @output, error : IO = @error, title : Nil | String = @title, width : Int32 = @width, height : Int32 = @height, dock_borders : Bool = @dock_borders, dock_contrast : Crysterm::DockContrast = @dock_contrast, always_propagate : Array(Tput::Key) = @always_propagate, propagate_keys : Bool = @propagate_keys, cursor : Crysterm::Screen::Cursor = @cursor, optimization : Crysterm::OptimizationFlag = @optimization, padding = nil, show_fps : Nil | Tput::Namespace::Point = @show_fps, force_unicode : Bool = @force_unicode, resize_interval : Time::Span = @resize_interval, terminfo : Bool | Unibilium::Terminfo = true) #

[View source]

Class Method Detail

def self.global(create : Bool = true) #

Creates and/or returns the "global" (first) created instance.

An alternative approach, which is currently not implemented, would be to hold the global in a class variable, and return it here. In that way, the choice of the default/global object at a particular time would be configurable in runtime.


[View source]
def self.instances #

List of existing instances.

For automatic management of this list, make sure that #bind is called at creation and #destroy at termination.

#bind does not have to be called explicitly because it happens during #initialize. #destroy does need to be called.


def self.total #

Returns number of created instances


[View source]

Instance Method Detail

def <<(element) #

[View source]
def >>(element) #

[View source]
def _border_stops : Hash(Int32, Bool) #

[View source]
def _border_stops=(_border_stops : Hash(Int32, Bool)) #

[View source]
def _ci : Int32 #

[View source]
def _ci=(_ci : Int32) #

[View source]
def _dock_borders #

[View source]
def _focus(cur : Widget, old : Widget | Nil = nil) #

[View source]
def _get_angle(lines, x, y) #

Returns appropriate angle char for point (y,x) in #lines

To operate, needs #lines (the 2d array of cells), and (y,x) point you're asking for.


[View source]
def _listen_keys(el : Widget | Nil = nil) #

And this is for the other/alternative method where the screen first gets the keys, then potentially passes onto children elements.


[View source]
def _render #

Real render


[View source]
def _saved_focus : Widget | Nil #

[View source]
def _saved_focus=(_saved_focus : Widget | Nil) #

[View source]
def aheight : Int32 #

Returns current screen height. This is now a local operation since we expect Display to push-update us.


[View source]
def alloc(dirty = false) #

Allocates screen buffers (a new pending/staging buffer and a new output buffer).

'Dirty' typically indicates that lines have to be redrawn. In this function's current implementation, if dirty is true it will re-crete the field of screen cells, not adjust the size of existing one.


[View source]
def always_propagate : Array(Tput::Key) #

Array of keys to ignore when keys are locked or grabbed. Useful for defining keys that will always execute their action (e.g. exit a program) regardless of whether keys are propagate.


[View source]
def always_propagate=(always_propagate : Array(Tput::Key)) #

Array of keys to ignore when keys are locked or grabbed. Useful for defining keys that will always execute their action (e.g. exit a program) regardless of whether keys are propagate.


[View source]
def apply_cursor #

Applies current cursor settings in @cursor to screen/display


[View source]
def attach(element) #

[View source]
def attr2code(code, cur, dfl) #

Converts an SGR string to our own attribute format.


[View source]
def awidth : Int32 #

Returns current screen width. This is now a local operation since we expect Display to push-update us.


[View source]
def blank_line(ch = ' ', dirty = false) #

[View source]
def clean_sides(el) #

Parse the sides of an element to determine whether an element has uniform cells on both sides. If it does, we can use CSR to optimize scrolling on a scrollable element. Not exactly sure how worthwhile this is. This will cause a performance/cpu-usage hit, but will it be less or greater than the performance hit of slow-rendering scrollable boxes with clean sides?


[View source]
def clear_region(xi, xl, yi, yl, override) #

Clears any chosen region on the screen.


[View source]
def code2attr(code) #

Converts our own attribute format to an SGR string.


[View source]

[View source]
def cursor_color(color : Tput::Color | Nil = nil) #

Sets cursor color


[View source]
def cursor_reset #

Re-enables and resets hardware cursor


[View source]
def cursor_shape(shape : Tput::CursorShape = Tput::CursorShape::Block, blink : Bool = false) #

Sets cursor shape


[View source]
def default_attr : Int32 #

XXX move somewhere else? Default cell attribute


[View source]
def default_attr=(default_attr : Int32) #

XXX move somewhere else? Default cell attribute


[View source]
def default_char : Char #

XXX move somewhere else? Default cell character


[View source]
def default_char=(default_char : Char) #

XXX move somewhere else? Default cell character


[View source]
def delete_bottom(top, bottom) #

Deletes line at bottom of screen.


[View source]
def delete_line(n, y, top, bottom) #

Deletes lines from the screen. (If CSR is used, it bypasses the output buffer.)


[View source]
def delete_line_nc(n, y, top, bottom) #

Deletes lines from the screen using ncurses-compatible method. (If CSR is used, it bypasses the output buffer.)

This is how ncurses does it. Scroll down (up cursor-wise). This will only work for top line deletion as opposed to arbitrary lines.


[View source]
def delete_top(top, bottom) #

Deletes line at top of screen.


[View source]
def destroy #

Destroys self and removes it from the global list of Screens. Also remove all global events relevant to the object. If no screens remain, the app is essentially reset to its initial state.


[View source]
def detach(element) #

[View source]
def dock_borders=(dock_borders : Bool) #

Automatically "dock" borders with other elements instead of overlapping, depending on position. These border-overlapped elements: ┌─────────┌─────────┐ │ box1 │ box2 │ └─────────└─────────┘ Become: ┌─────────┬─────────┐ │ box1 │ box2 │ └─────────┴─────────┘


[View source]
def dock_borders? : Bool #

Automatically "dock" borders with other elements instead of overlapping, depending on position. These border-overlapped elements: ┌─────────┌─────────┐ │ box1 │ box2 │ └─────────└─────────┘ Become: ┌─────────┬─────────┐ │ box1 │ box2 │ └─────────┴─────────┘


[View source]
def draw(start = 0, stop = @lines.size - 1) #

Draws the screen based on the contents of in-memory grid of cells (@lines).


[View source]
def emit_key(el, e : Event) #

Emits a Event::KeyPress as usual and also emits an event for the individual key, if any.

This allows listeners to not only listen for a generic Event::KeyPress and then check for #key, but they can directly listen for e.g. Event::KeyPress::CtrlP.


[View source]
def enter #

[View source]
def error : IO #

Error IO. (Could be used for redirecting error output to a particular widget.)


[View source]
def error=(error : IO) #

Error IO. (Could be used for redirecting error output to a particular widget.)


[View source]
def exec(screen : Crysterm::Screen | Nil = nil) #

Displays the main screen, set up IO hooks, and starts the main loop.

This is similar to how it is done in the Qt framework.

This function will render the specified screen or the first Screen assigned to Display.


[View source]
def fill_region(attr, ch, xi, xl, yi, yl, override = false) #

Fills any chosen region on the screen with chosen character and attributes.


[View source]
def focus(el) #

Makes el become the current/top element in the focus history list.


[View source]
def focus_next #

Focuses next element in the list of focusable elements.


[View source]
def focus_offset(offset) #

Focuses an element by an offset in the list of focusable elements.

E.g. focus_offset 1 moves focus to the next focusable element. focus_offset 3 moves focus 3 focusable elements further.

If the end of list of focusable elements is reached before the item to focus is found, the search continues from the beginning.


[View source]
def focus_pop #

Removes focus from the current element and focuses the element that was previously in focus.


[View source]
def focus_previous #

Focuses previous element in the list of focusable elements.


[View source]
def focus_push(el) #

Focuses element el. Equivalent to @display.focused = el.


[View source]
def focused : Widget | Nil #

Returns the current/top element from the focus history list.


[View source]
def force_unicode=(force_unicode : Bool) #

Force Unicode (UTF-8) even if terminfo auto-detection did not find support for it?


[View source]
def force_unicode? : Bool #

Force Unicode (UTF-8) even if terminfo auto-detection did not find support for it?


[View source]
def grab_keys=(grab_keys : Bool) #

Is the focused element grab and receiving all keypresses?


[View source]
def grab_keys? : Bool #

Is the focused element grab and receiving all keypresses?


[View source]
def height : Int32 #

Display height

TODO make these check @output, not STDOUT which is probably used. Also see how urwid does the size check


[View source]
def height=(height : Int32) #

Display height

TODO make these check @output, not STDOUT which is probably used. Also see how urwid does the size check


[View source]
def hide_cursor #

Hides cursor


[View source]
def ibottom #

Amount of space taken by decorations on bottom, to be subtracted from widget's total height


[View source]
def iheight #

Returns current screen height.


[View source]
def ileft #

Amount of space taken by decorations on the left side, to be subtracted from widget's total width


[View source]
def input : IO #

Input IO


[View source]
def input=(input : IO) #

Input IO


[View source]
def insert(element, i = -1) #
Description copied from module Crysterm::Mixin::Children

Inserts element into list of children widgets


[View source]
def insert_bottom(top, bottom) #

Inserts line at bottom of screen.


[View source]
def insert_line(n, y, top, bottom) #

Inserts lines into the screen. (If CSR is used, it bypasses the output buffer.)


[View source]
def insert_line_nc(n, y, top, bottom) #

Inserts lines into the screen using ncurses-compatible method. (If CSR is used, it bypasses the output buffer.)

This is how ncurses does it. Scroll down (up cursor-wise). This will only work for top line deletion as opposed to arbitrary lines.


[View source]
def insert_top(top, bottom) #

Inserts line at top of screen.


[View source]
def interval : Float64 #

[View source]
def interval=(interval : Float64) #

[View source]
def iright #

Amount of space taken by decorations on the right side, to be subtracted from widget's total width


[View source]
def itop #

Amount of space taken by decorations on top, to be subtracted from widget's total height


[View source]
def iwidth #

Returns current screen width.


[View source]
def last_rendered_position #

TODO Instead of self, this should just return an object which reports the position like LPos. But until screen is always from (0,0) to (height,width) that's not necessary.


[View source]
def leave #

[View source]
def lines : Array(Crysterm::Screen::Row) #

[View source]
def lines=(lines : Array(Crysterm::Screen::Row)) #

[View source]
def listen #

Sets up IO listeners for keyboard (and mouse, but mouse is currently unsupported).


[View source]
def listen_keys #

Starts emitting Event::KeyPress events on key presses.

Keys are listened for in a separate Fiber. There should be at most 1.


[View source]
def new_method(*args) #

def olines : Array(Crysterm::Screen::Row) #

[View source]
def olines=(olines : Array(Crysterm::Screen::Row)) #

[View source]
def on_attach(e) #

[View source]
def on_destroy(e) #

Destroys current Display.


[View source]
def on_detach(e) #

[View source]
def on_resize(e) #

[View source]
def optimization : OptimizationFlag #

Optimization flags to use for rendering and/or drawing. XXX See also a TODO item related to dynamically deciding on default flags.


[View source]
def optimization=(optimization : OptimizationFlag) #

Optimization flags to use for rendering and/or drawing. XXX See also a TODO item related to dynamically deciding on default flags.


[View source]
def output : IO #

Output IO


[View source]
def output=(output : IO) #

Output IO


[View source]
def overflow : Crysterm::Overflow #

Specifies what to do with "overflowing" (too large) widgets. The default setting of Overflow::Ignore simply ignores the overflow and renders the parts that are in view.


[View source]
def overflow=(overflow : Crysterm::Overflow) #

Specifies what to do with "overflowing" (too large) widgets. The default setting of Overflow::Ignore simply ignores the overflow and renders the parts that are in view.


[View source]
def padding : Crysterm::Padding #

For compatibility with widgets. But, as a side-effect, screens can have padding! If you define widget at position (0,0), that will be counted after padding. (We leave this at nil for no padding. If we used Padding.new that'd create a 1 cell padding by default.)


[View source]
def padding=(padding : Crysterm::Padding) #

For compatibility with widgets. But, as a side-effect, screens can have padding! If you define widget at position (0,0), that will be counted after padding. (We leave this at nil for no padding. If we used Padding.new that'd create a 1 cell padding by default.)


[View source]
def post_enter #

[View source]
def propagate_keys=(propagate_keys : Bool) #

Are keypresses being propagated further, or (except ignored ones) not propagated?


[View source]
def propagate_keys? : Bool #

Are keypresses being propagated further, or (except ignored ones) not propagated?


[View source]
def realloc #

Reallocates screen buffers and clear the screen.


[View source]
def remove(element) #
Description copied from module Crysterm::Mixin::Children

Removes element from list of children widgets


[View source]
def render #

Delayed render (user render)


[View source]
def render_loop #

[View source]
def resize #

Re-reads current size of all Displays and triggers redraw of all Screens.

NOTE There is currently no detection for which Display the resize has happened on, so a resize in any one managed display causes an update and redraw of all displays.


[View source]
def resize_interval : Time::Span #

Amount of time to wait before redrawing the screen, after the last successive terminal resize event is received.

The value used in Qt is 0.3 seconds. The value commonly used in console apps is 0.2 seconds. Yet another choice could be the frame rate, i.e. 1/29 seconds.

This ensures the resizing/redrawing is done only once, once resizing is over. To have redraws happen even while resizing is going on, reduce this interval.


[View source]
def resize_interval=(resize_interval : Time::Span) #

Amount of time to wait before redrawing the screen, after the last successive terminal resize event is received.

The value used in Qt is 0.3 seconds. The value commonly used in console apps is 0.2 seconds. Yet another choice could be the frame rate, i.e. 1/29 seconds.

This ensures the resizing/redrawing is done only once, once resizing is over. To have redraws happen even while resizing is going on, reduce this interval.


[View source]
def restore_focus #

Restores focus to the previously saved focused element.


[View source]
def rewind_focus #

"Rewinds" focus to the most recent visible and attached element.

As a side-effect, prunes the focus history list.


[View source]
def save_focus #

Saves/remembers the currently focused element.


[View source]
def schedule_render #

[View source]
def screenshot(xi = 0, xl = awidth, yi = 0, yl = aheight, term = false) #

[View source]
def send_focus : Bool #

Send focus events after mouse is enabled?


[View source]
def send_focus=(send_focus : Bool) #

Send focus events after mouse is enabled?


[View source]
def show_avg=(show_avg : Bool) #

Include displaying averages in FPS display. If this setting is false, only current/ individual frame rates are shown, without values for averages over 30 frames.


[View source]
def show_avg? : Bool #

Include displaying averages in FPS display. If this setting is false, only current/ individual frame rates are shown, without values for averages over 30 frames.


[View source]
def show_cursor #

Shows cursor


[View source]
def show_fps : Tput::Point | Nil #

Which position on the screen should be used to display FPS stats. Nil disables. XXX Currently this is enabled since Crysterm is under development.


[View source]
def show_fps=(show_fps : Tput::Point | Nil) #

Which position on the screen should be used to display FPS stats. Nil disables. XXX Currently this is enabled since Crysterm is under development.


[View source]
def title : String | Nil #

Screen title, if/when applicable


[View source]
def title=(title : String | Nil) #

Screen title, if/when applicable


[View source]
def tput : Tput #

Instance of Tput, used for generating term control sequences.


[View source]
def width : Int32 #

Display width

TODO make these check @output, not STDOUT which is probably used. Also see how urwid does the size check


[View source]
def width=(width : Int32) #

Display width

TODO make these check @output, not STDOUT which is probably used. Also see how urwid does the size check


[View source]