tw
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.")