RXLV_HELP: procedure 
/* Help stuff here */
return

RXLV_MAIN: procedure expose viewline. rxlv.
parse arg titletxt, inlinechars

/* Reset key */
rxlv.key = ''

/* Which is bigger - win rows or lines in stemvar? */
if rxlv.disprows > viewline.0 then rxlv.actrows = viewline.0
else rxlv.actrows = rxlv.disprows

/* Get current mouse coordinates */
if ~rxlv.opened? then do
    call forbid()
    mousex = c2d(import(offset(rxlv.screen, 18), 2)) - 50      /* Screen->MouseX */
    mousey = c2d(import(offset(rxlv.screen, 16), 2)) - 50      /* Screen->MouseY */
    call permit()

    /* Open the listview */
    /* Open the listview */
    if ~open(rxlv.win, 'RAW:'mousex'/'mousey'/'rxlv.width'/'rxlv.height'/'titletxt'/NOSIZE', 'w') then do
        say 'Could not open listview window!'
        exit 10
    end
    call writech(rxlv.win, rxlv.nocursor||rxlv.nowordwrap)
    /* Initialize window */
    if viewline.0 > 0 then do
        rxlv.row = 1 
        rxlv.var = 1
        rxlv.topvar = 1 
        call writech(rxlv.win, rxlv_getlighty(rxlv.row, rxlv.var)||rxlv.nl||rxlv_getpage(rxlv.var + 1))
    end
    rxlv.opened? = 1
end

/* Do ze stuff */
do forever
    rxlv.oldrow = rxlv.row 
    rxlv.oldvar = rxlv.var

    char = readch(rxlv.win, 1)
    select
        when char = rxlv.csi then do
            char = readch(rxlv.win, 1)
            select
                when viewline.0 < 2 then nop
                when char = rxlv.cursordown then do
                    if rxlv.oldvar ~= viewline.0 then do
                        line = rxlv_getunlighty()
                        rxlv.var = rxlv.var + 1

                        if rxlv.oldrow < rxlv.actrows then rxlv.row = rxlv.row + 1 
                        else do
                            line = line||rxlv.nl
                            rxlv.row = rxlv.actrows
                            rxlv.topvar = rxlv.topvar + 1
                        end
                        call writech(rxlv.win, line||rxlv_getlighty())
                    end
                    else call rxlv_top()
                end  
                when char = rxlv.cursorup then do
                    if rxlv.oldvar ~= 1 then do
                        line = rxlv_getunlighty()
                        rxlv.var = rxlv.var - 1

                        if rxlv.oldrow ~= 1 then do
                            rxlv.row = rxlv.row - 1
                            call writech(rxlv.win, line||rxlv_getlighty())
                        end
                        else do
                            rxlv.row = 1 
                            rxlv.topvar = rxlv.topvar - 1
                            call writech(rxlv.win, line||rxlv_getlighty()||rxlv.nl||rxlv_getpage(rxlv.var + 1))
                        end            
                    end
                    else call rxlv_bottom()                  
                end
                when char = rxlv.scursorup then do
                    if rxlv.oldvar ~= 1 then do
                        rxlv.row = 1
                        rxlv.var = rxlv.topvar

                        if rxlv.oldrow = 1 then do
                            if rxlv.oldvar - rxlv.actrows < 1 then rxlv.topvar = 1
                            else rxlv.topvar = rxlv.oldvar - rxlv.actrows
                            rxlv.var = rxlv.topvar
                            call writech(rxlv.win, rxlv.cls||rxlv_getlighty()||rxlv.nl||rxlv_getpage(rxlv.topvar + 1))
                        end
                        else call writech(rxlv.win, rxlv_getunlighty()||rxlv_getlighty())
                    end
                    else call rxlv_bottom()                  
                end
                when char = rxlv.scursordown then do
                    if rxlv.oldvar ~= viewline.0 then do
                        rxlv.row = rxlv.actrows

                        if rxlv.oldrow = rxlv.actrows then do
                            if rxlv.oldvar + rxlv.actrows > viewline.0 then rxlv.topvar = viewline.0 - (rxlv.actrows - 1)
                            else rxlv.topvar = rxlv.oldvar + 1
                            rxlv.var = min(viewline.0, rxlv.topvar + (rxlv.actrows - 1))
                            call writech(rxlv.win, rxlv.cls||rxlv_getpage(rxlv.topvar)||rxlv.nl||rxlv_getlighty())
                        end
                        else do
                            rxlv.var = (rxlv.topvar + rxlv.actrows) - 1
                            call writech(rxlv.win, rxlv_getunlighty()||rxlv_getlighty())
                        end
                    end
                    else call rxlv_top()
                end
                otherwise nop
            end
        end
        when char = rxlv.esc then do
            rxlv.key = 'ESC'
            return rxlv_val()
        end
        when char = rxlv.cr then do
            rxlv.key = 'RET'
            return rxlv_val()
        end
        when char = rxlv.del then do
            rxlv.key = 'DEL'
            return rxlv_val()
        end
        when pos(char, inlinechars) > 0 then do
            rxlv.key = char
            return rxlv_val()
        end
        when char = rxlv.help then call rxlv_help()
        otherwise nop
    end
end


RXLV_VAL: procedure expose rxlv. viewline.
if viewline.0 = 0 then return 0
return rxlv.oldvar


RXLV_TOP: procedure expose rxlv. viewline.
rxlv.var = 1
rxlv.row = 1

if rxlv.topvar = 1 then do   /* Just move to top */
    line = rxlv_getunlighty()
    call writech(rxlv.win, line||rxlv_getlighty())
end
else do
    rxlv.topvar = 1
    call writech(rxlv.win, rxlv.cls||rxlv_getlighty()||rxlv.nl||rxlv_getpage(rxlv.var + 1))
end
return


RXLV_BOTTOM: procedure expose rxlv. viewline.
rxlv.var = viewline.0

if viewline.0 <= rxlv.actrows then do 
    line = rxlv_getunlighty()
    rxlv.row = viewline.0
    call writech(rxlv.win, line||rxlv_getlighty())
end
else do
    rxlv.row = rxlv.actrows
    rxlv.topvar = (viewline.0 - rxlv.actrows) + 1
    call writech(rxlv.win, rxlv.cls||rxlv_getpage(rxlv.topvar)||rxlv.nl||rxlv_getlighty())
end
return


RXLV_GETPAGE: procedure expose viewline. rxlv.
if viewline.0 = 1 then return ''

top = arg(1)
page = ''
do y = 1 to rxlv.actrows - 2                    /* Lines between first and last */
    page = page||viewline.top||rxlv.nl
    top = top + 1
end 
page = page||viewline.top                       /* No newline after last line */
return page


RXLV_GETUNLIGHTY: procedure expose rxlv. viewline. 
var = rxlv.oldvar
return rxlv.csi||rxlv.oldrow'H'viewline.var


RXLV_GETLIGHTY: procedure expose rxlv. viewline. 
var = rxlv.var
return rxlv.csi||rxlv.row'H'rxlv.hilite||viewline.var||rxlv.off


RXLV_CLOSEWIN: procedure expose rxlv.
if rxlv.opened? then do
    call close(rxlv.win)
    rxlv.opened? = 0
end
return 


RXLV_INIT: procedure expose rxlv.
/* Hardcoded minimum values */
rxlv.width = max(100, rxlv.width)
rxlv.height = max(50, rxlv.height)

/* ANSI stuff */
rxlv.csi = '9b'x  ; rxlv.esc = '1b'x
rxlv.help = '7e'x ; rxlv.del = '7f'x
rxlv.nl = '0a'x   ; rxlv.cr = '0d'x
rxlv.off = rxlv.csi||'0m' 
rxlv.topleft = rxlv.csi'48'x 
rxlv.cls = rxlv.csi'H'rxlv.csi'J'
rxlv.hilite = rxlv.csi'43;32m'
rxlv.nowordwrap = rxlv.csi||'3f376c'x
rxlv.nocursor = rxlv.csi||'302070'x 
rxlv.cursorup = '41'x  ; rxlv.cursordown = '42'x 
rxlv.scursorup = '54'x ; rxlv.scursordown = '53'x
rxlv.win = 'listwin'

/* GUI constants */
guiheight = 7 ; guiwidth = 8

/* Font info */
intui = showlist(l, 'intuition.library',, a)
call forbid()
rxlv.screen = next(intui, 56)               /* IntuitionBase->ActiveScreen */
font = next(rxlv.screen, 136)               /* Screen->RastPort.Font */
fonty = c2d(import(offset(font, 20), 2))    /* Font->YSize */
fontx = c2d(import(offset(font, 24), 2))    /* Font->XSize */
call permit()

/* Listview width */
do while (rxlv.width - guiwidth) // fontx ~= 0 
    rxlv.width = rxlv.width + 1 
end
rxlv.dispcols = ((rxlv.width - guiwidth) % fontx)
rxlv.filler = copies(' ', rxlv.dispcols)

/* Listview height */
const = guiheight + fonty
do while (rxlv.height - const) // fonty ~= 0 
    rxlv.height = rxlv.height + 1 
end
rxlv.disprows = (rxlv.height - const) % fonty

rxlv.opened? = 0
return
