frame_t Derived Type

type, public :: frame_t

A screen’s worth of text lines, rendered by diffing against the last.

The model is “set every line, render, repeat”. render compares each line with what was last rendered and emits moves and rewrites only for the rows that changed, so an otherwise idle board that updates a clock writes one line rather than twenty-four. That is what makes the simple model flicker-free.


Inherits

type~~frame_t~~InheritsGraph type~frame_t frame_t type~string_type string_type type~frame_t->type~string_type current, shown

Components

Type Visibility Attributes Name Initial
integer(kind=default_int), private :: cols = 0_default_int

Width in code points; set_line truncates to it.

type(string_type), private, allocatable :: current(:)

Lines as set since the last render.

string_type rather than character(len=:), allocatable :: (:) for two reasons, both learned the hard way.

A deferred-length allocatable array cannot be blanked with a whole-array = "": F2018 10.2.1.3 deallocates and reallocates an allocatable whose length type parameter differs from the expression’s, so that assignment sets the length to zero. GNU, AOCC and LFortran keep the length and blank-pad; Intel and NVIDIA reallocate. Both readings are defensible and the construct is therefore unusable here.

And a fixed row length has to be guessed. Escape sequences make a styled line far longer in bytes than in columns – per-character colouring runs to about ten bytes a column – so any constant multiple of the width is a cap waiting to truncate someone’s row.

logical, private :: full_redraw = .true.

Set by resize and invalidate; makes the next render emit every row regardless of the diff.

integer(kind=default_int), private :: rows = 0_default_int

Number of lines.

type(string_type), private, allocatable :: shown(:)

Lines as of the last render, for diffing.


Type-Bound Procedures

procedure, public :: col_count => frame_col_count

  • private pure function frame_col_count(this) result(c)

    Width the frame truncates to.

    Arguments

    Type IntentOptional Attributes Name
    class(frame_t), intent(in) :: this

    Return Value integer(kind=default_int)

procedure, public :: invalidate => frame_invalidate

  • private subroutine frame_invalidate(this)

    Force the next render to emit every row.

    Read more…

    Arguments

    Type IntentOptional Attributes Name
    class(frame_t), intent(inout) :: this

procedure, public :: render => frame_render

  • private function frame_render(this) result(output)

    The escape sequence that brings the screen up to date.

    Read more…

    Arguments

    Type IntentOptional Attributes Name
    class(frame_t), intent(inout) :: this

    Return Value character(len=:), allocatable

procedure, public :: resize => frame_resize

  • private subroutine frame_resize(this, rows, cols)

    Set the frame’s dimensions, discarding the diff.

    Read more…

    Arguments

    Type IntentOptional Attributes Name
    class(frame_t), intent(inout) :: this
    integer(kind=default_int), intent(in) :: rows

    Number of lines; below 0 is treated as 0.

    integer(kind=default_int), intent(in) :: cols

    Width in code points; below 0 is treated as 0.

procedure, public :: row_count => frame_row_count

  • private pure function frame_row_count(this) result(r)

    Number of lines the frame holds.

    Arguments

    Type IntentOptional Attributes Name
    class(frame_t), intent(in) :: this

    Return Value integer(kind=default_int)

procedure, public :: set_line => frame_set_line

  • private subroutine frame_set_line(this, row, text)

    Set one line, truncated to the frame width in code points.

    Read more…

    Arguments

    Type IntentOptional Attributes Name
    class(frame_t), intent(inout) :: this
    integer(kind=default_int), intent(in) :: row

    One-based row.

    character(len=*), intent(in) :: text

    Text for the row.

Source Code

   type :: frame_t
      !! A screen's worth of text lines, rendered by diffing against the last.
      !!
      !! The model is "set every line, render, repeat". `render` compares each
      !! line with what was last rendered and emits moves and rewrites only
      !! for the rows that changed, so an otherwise idle board that updates a
      !! clock writes one line rather than twenty-four. That is what makes the
      !! simple model flicker-free.
      private
      type(string_type), allocatable :: current(:)
         !! Lines as set since the last render.
         !!
         !! `string_type` rather than `character(len=:), allocatable :: (:)`
         !! for two reasons, both learned the hard way.
         !!
         !! A deferred-length allocatable *array* cannot be blanked with a
         !! whole-array `= ""`: F2018 10.2.1.3 deallocates and reallocates an
         !! allocatable whose length type parameter differs from the
         !! expression's, so that assignment sets the length to zero. GNU,
         !! AOCC and LFortran keep the length and blank-pad; Intel and NVIDIA
         !! reallocate. Both readings are defensible and the construct is
         !! therefore unusable here.
         !!
         !! And a fixed row length has to be guessed. Escape sequences make a
         !! styled line far longer in bytes than in columns -- per-character
         !! colouring runs to about ten bytes a column -- so any constant
         !! multiple of the width is a cap waiting to truncate someone's row.
      type(string_type), allocatable :: shown(:)
         !! Lines as of the last render, for diffing.
      integer(default_int) :: rows = 0_default_int
         !! Number of lines.
      integer(default_int) :: cols = 0_default_int
         !! Width in code points; `set_line` truncates to it.
      logical :: full_redraw = .true.
         !! Set by `resize` and `invalidate`; makes the next render emit every
         !! row regardless of the diff.
   contains
      procedure :: resize => frame_resize
      procedure :: set_line => frame_set_line
      procedure :: render => frame_render
      procedure :: invalidate => frame_invalidate
      procedure :: row_count => frame_row_count
      procedure :: col_count => frame_col_count
   end type frame_t