tw

Description of the page content

Text windows for X11-Basic console programs.

Tags:

tw stands for “text windows”; it implements text windows in X11-Basic. It lets definition of a console text window, any size or position, and print left-justified paragraphs with automatic scrolling. It's still under development but works fine.

tw started as part of a bigger project still under development, a text adventure game, but soon was extracted as a re-usable module.

Source code

' tw.xbas

' tw
' Version 0.1.0+201707291351
' See change log at the end of the file

' Text windows for X11-Basic.
' <http://programandala.net/en.program.tw.html>

' Author: Marcos Cruz (programandala.net), 2013,2014,2015,2017 

' You may do whatever you want with this work, so long as you
' retain all copyright, authorship and credit notices and this
' license in all redistributed copies and derived works.  There
' is no warranty.

' ==============================================================
' Text output {{{1

procedure tw_init

  ' Init the deafult values.

  let tw_indentation%=2 ! spaces
  ! XXX FIXME 0 still prints a blank line:
  let tw_blank_lines_between_paragraphs%=0
  return

procedure tw_new(row%,col%,cols%,rows%)

  ' Define the text window.

  @tw_size(cols%,rows%)
  @tw_frame_locate(row%,col%)
  @tw_home
  return

procedure tw_home

  ' Set the text window cursor to home.

  @tw_locate(0,0)
  return

procedure tw_locate(row%,col%)

  ' Set the text window cursor coordinates.

  let tw_row%=row%
  let tw_col%=col%
  return

procedure tw_frame_locate(row%,col%)

  ' Set the text window frame coordinates.

  let tw_frame_row%=row% ! top screen row
  let tw_frame_col%=col% ! left screen col
  return

procedure tw_size(cols%,rows%)

  ' Set the size of the text window.

  let tw_cols%=cols%
  let tw_rows%=rows%
  let tw_last_row%=rows%-1
  dim tw_line$(rows%)
  @tw_wipe
  return

function tw_row_is_in_screen%(row%)

  ' Is a window row number in the screen limits?

  return row%>=0 and row%<=rows

procedure tw_dump_line(row%)

  ' Dump a line of the text window to the screen.

  local actual_row%
  local visible_len%
  local first_visible_char%
  let actual_row%=tw_frame_row%+row%
  #if @tw_row_is_in_screen%(actual_row%)
  if true ! XXX debug check
    let first_visible_char%=abs(0-tw_frame_col%)+1 ! XXX TODO
    let visible_len%=min(tw_cols%,cols-tw_frame_col%)
    ' XXX TODO check also if tw_col% is outside the screen
    #if visible_len%
    if true ! XXX debug check
      locate actual_row%,tw_frame_col%
      #print left$(tw_line$(row%),visible_len%)
      #print row% using "0#>"; ! XXX debug check
      #print "{";left$(tw_line$(row%),visible_len%);"} r=";tw_row% using "0#";" c=";tw_col% using "0#"; ! XXX debug check
      #print left$(tw_line$(row%),visible_len%);"| r=";tw_row% using "0#";" c=";tw_col% using "0#"; ! XXX debug check
      print left$(tw_line$(row%),visible_len%);
      flush
    endif
  endif
  return

procedure tw_dump

  ' Dump the content of the text window to the screen.

  local row%
  for row%=0 to tw_last_row%
    @tw_dump_line(row%)
  next
  return

procedure tw_scroll

  ' Scroll the content of the text window one line up.

  local row%
  for row%=0 to tw_last_row%-1
    let tw_line$(row%)=tw_line$(row%+1)
    @tw_dump_line(row%)
  next
  @tw_wipe_line(tw_last_row%)
  @tw_dump_line(tw_last_row%)
  return

procedure tw_wipe_line(row%)

  ' Wipe the content of a line of the text window,
  ' but do not change the screen.

  let tw_line$(row%)=space$(tw_cols%)
  return

procedure tw_wipe

  ' Wipe the content of the text window,
  ' but do not change the screen.

  local row%
  for row%=0 to tw_last_row%
    @tw_wipe_line(row%)
  next
  return

procedure tw_cls

  ' Clear the text window.

  @tw_wipe
  @tw_dump
  @tw_home
  return

function tw_cursor_is_at_the_left%

  ' Is the text window cursor at the first column?

  return tw_col%=tw_frame_col%

function tw_cursor_is_at_the_top%

  ' Is the text window cursor at the first row?

  #return tw_row%=tw_frame_row%  ! XXX old
  #print tw_row% ! XXX debug check
  #pause 3 ! XXX debug check
  return tw_row%=0

function tw_cursor_is_at_the_bottom%

  ' Is the text window cursor at the last row?

  return tw_row%=tw_last_row%

procedure tw_do_cr

  ' Do a carriage return.

  if @tw_cursor_is_at_the_bottom%
    @tw_scroll
  else
    inc tw_row%
    if tw_row%>tw_last_row%
      @tw_scroll
    endif
  endif
  let tw_col%=tw_frame_col%
  return

procedure tw_cr

  ' Do a carriage return, if needed.

  if not @tw_cursor_is_at_the_left%
    @tw_do_cr
  endif
  return

procedure tw_print(text$)

  ' Print a text at the current cursor position.
  ' The text is supposed to fit in the current row;
  ' otherwise it's truncated.

  let tw_line$(tw_row%)=\
    left$(tw_line$(tw_row%),tw_col%)+\
    text$+\
    right$(tw_line$(tw_row%),tw_cols%-tw_col%-len(text$))
  add tw_col%,len(text$)
  let tw_col%=min(tw_col%,cols-1) ! XXX FIXME
  @tw_dump_line(tw_row%)
  return

procedure tw_indent

  ' Do a carriage return and indent.
  ' XXX TODO rename

#  if not @tw_cursor_is_at_the_top%
    ' Note: an additional space will be shown before the first
    ' word of the paragraph, so x spaces here mean x+1 spaces
    ' of indentation:
    local row%
    for row%=0 to tw_blank_lines_between_paragraphs%-1
      @tw_do_cr
    next
    @tw_print(space$(max(tw_indentation%-1,0)))
#  endif
  return

function tw_free_cols%

  ' Number of free columns in the current row of the window.

  return tw_cols%-tw_col%-1

procedure tw_p(text$)

  ' Print a text, left justified, from the current cursor
  ' position.

  local a_word$
  let text$=text$+" "
  do
    split text$," ",0,a_word$,text$
    if (@tw_free_cols%-1)>=len(a_word$)
      if not @tw_cursor_is_at_the_left%
        @tw_print(" ")
      endif
    else
      @tw_cr
    endif
    @tw_print(a_word$)
    exit if text$=""
  loop
  return

procedure tw_p_(text$)

  ' Start a new paragraph.

  @tw_cr
  @tw_indent
  @tw_p(text$)
  return

' ==============================================================
' Change log {{{1

' 2013-05-22:
'
' Start, as part of a text adventure game project, Fifi.
'
' 2013-05-24:
'
' Fix: the parameters of 'tw_locate()' and 'tw_frame_locate()'
' were in wrong order.
'
' Change: 'tw_wipe_line()' factored from 'tw_wipe()'.  Fix:
' 'tw_scroll' does not empty the last line any more, but
' properly wipes it with spaces.
'
' New: one single command, 'tw_new', creates the window.
'
' Fix: 'tw_print' limits tw_row% to cols-1.
'
' Improvement: 'tw_dump_line' does nothing if the line is out of
' the screen, what (when complemented with the col check) will
' let the text window to be partially or totally out of the
' screen.
'
' Improvement: 'tw_dump_line' does not print the part of the
' line that overflows at the right of the screen.
'
' Change: the code is moved from "Fifi" to an independent file,
' in order to reuse it as a module ("tw").
'
' 2013-09-06:
'
' Fix: Some typos in the development history.
'
' 2013-09-07:
'
' Fix: The input line is cleared after every input.
'
' Fix: 'tw_scroll' decremented tw_row% at the end, what ruined
' the effect.  Change: the parameters of 'tw_locate()' and
' 'tw_frame_locate()' have been inverted, after X11-Basic's
' 'locate'.
'
' 2013-09-26:
'
' Fix: 'flush' added to 'tw_dump_line' in order to prevent the
' effects of buffered output.
'
' 2014-03-15:
'
' Some little changes in the source code layout.
'
' 2014-12-12:
'
' Some changes in the comments and credits. 'endfunction' is
' removed, since it's not mandatory.
'
' 2015-03-02:
'
' New: 'tw_blank_lines_between_paragraphs%' to separate the
' paragraphs. Not fully finished yet.
'
' 2017-07-29:
'
' Move initialization commands to new procedure `tw_init`.
' Change version numbering after Semantic Versioning
' (http://semver.org). Change license.

' vim: filetype=x11basic

Usage example

The following code consists of code pieces extracted from a project that uses tw:
  merge "tw.xbas"

  ' Window position and size:
  let frame_col%=2
  let frame_row%=2
  let frame_cols%=cols-4
  let frame_rows%=rows-6

  ' Window definition:
  @tw_new(\
    frame_col%,frame_row%,\
    frame_cols%,frame_rows%)

  ' Printing a left-justified paragraph in the window:
  @tw_p_("Suddenly, a man goes out from the house.")
  @tw_p("He locks the door behind him")
  @tw_p("and then walks away.")

Downloads

Related pages

wt
Text wrapping module for X11-Basic and MBim.