cx16 fileselector improvements

This commit is contained in:
Irmen de Jong 2025-01-02 22:17:56 +01:00
parent 3b4b37f16b
commit b014facbd3
7 changed files with 168 additions and 60 deletions

View File

@ -35,6 +35,8 @@
; Those are all shared in the different tasks! You HAVE to use a mechanism around the userdata value (pointer?) to keep separate state elsewhere!
coroutines {
%option ignore_unused
const ubyte MAX_TASKS = 64
uword[MAX_TASKS] tasklist
uword[MAX_TASKS] userdatas

View File

@ -161,6 +161,7 @@ io_error:
; Files in the buffer are separated by a 0 byte. You can provide an optional pattern to match against.
; After the last filename one additional 0 byte is placed to indicate the end of the list.
; Returns number of files (it skips 'dir' entries i.e. subdirectories).
; Note: NO case-folding is done in this routine! (unlike DOS"$ which does case folding on the basic prompt)
; Also sets carry on exit: Carry clear = all files returned, Carry set = directory has more files that didn't fit in the buffer.
; Note that no list of pointers of some form is returned, the names are just squashed together.
; If you really need a list of pointers to the names, that is pretty straightforward to construct by iterating over the names
@ -222,6 +223,7 @@ io_error:
; -- retrieve the next entry from an iterative file listing session.
; results will be found in list_blocks, list_filename, and list_filetype.
; if it returns false though, there are no more entries (or an error occurred).
; Note: NO case-folding is done in this routine! (unlike DOS"$ which does case folding on the basic prompt)
if not iteration_in_progress
return false

View File

@ -484,6 +484,7 @@ extsub $C006 = x16edit_loadfile_options(ubyte firstbank @X, ubyte lastbank @Y, s
uword disknumberAndColors @R3, uword headerAndStatusColors @R4) clobbers(A,X,Y)
; Audio (rom bank 10)
; NOTE: because these are auto-banked, you should not call them from an IRQ handler routine (due to jsrfar race condition).
extsub @bank 10 $C09F = audio_init() clobbers(A,X,Y) -> bool @Pc ; (re)initialize both vera PSG and YM audio chips
extsub @bank 10 $C000 = bas_fmfreq(ubyte channel @A, uword freq @XY, bool noretrigger @Pc) clobbers(A,X,Y) -> bool @Pc
extsub @bank 10 $C003 = bas_fmnote(ubyte channel @A, ubyte note @X, ubyte fracsemitone @Y, bool noretrigger @Pc) clobbers(A,X,Y) -> bool @Pc

View File

@ -1,6 +1,7 @@
; **experimental** data sorting routines, API subject to change!!
sorting {
%option ignore_unused
; GNOME SORT is tiny and extremely fast if the initial values are already almost sorted.
; SHELL SORT is quite a bit faster if the initial values are more randomly distributed.

View File

@ -270,7 +270,7 @@ On the Commander X16 the stack and ringbuffer will use a HiRAM bank instead of s
you have to initialize that via the init(bank) routine.
Read the `buffers source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/diskio.p8>`_
to see what's in there. Note that the init() routines have that extra bank parameter on the cx16.
to see what's in there. Note that the init() routines have that extra bank parameter on the X16.
compression (slightly experimental)
@ -502,6 +502,8 @@ floats
.. note::
Floating point support is only available on c64, cx16 and virtual targets for now.
On the X16, make sure rom bank 4 is still active before doing floationg point operations (it's the bank that contains the fp routines).
On the C64, you have to make sure the Basic ROM is still banked in (same reason).
Provides definitions for the ROM/Kernal subroutines and utility routines dealing with floating point variables.
@ -599,7 +601,7 @@ Provides definitions for the ROM/Kernal subroutines and utility routines dealing
gfx_lores and gfx_hires (cx16 only)
-----------------------------------
Full-screen multicolor bitmap graphics routines, available on the Cx16 machine only.
Full-screen multicolor bitmap graphics routines, available on the X16 machine only.
- gfx_lores: optimized routines for 320x240 256 color bitmap graphics mode. Compatible with X16 screen mode 128.
- gfx_hires: optimized routines for 640x480 4 color bitmap graphics mode
@ -626,7 +628,7 @@ Bitmap graphics routines:
This library is available both on the C64 and the cx16.
It uses the ROM based graphics routines on the latter, and it is a very small library because of that.
On the cx16 there's also various other graphics modules if you want more features and different screen modes. See below for those.
On the X16 there's also various other graphics modules if you want more features and different screen modes. See below for those.
Read the `graphics source code <https://github.com/irmen/prog8/tree/master/compiler/res/prog8lib/c64/graphics.p8>`_
to see what's in there. (Note: slight variations for different compiler targets)
@ -783,7 +785,7 @@ but perhaps the provided ones can be of service too.
monogfx (cx16 and virtual)
---------------------------
Full-screen lores or hires monochrome bitmap graphics routines, available on the Cx16 machine only.
Full-screen lores or hires monochrome bitmap graphics routines, available on the X16 machine only.
- two resolutions: lores 320*240 or hires 640*480 bitmap mode
- optimized routines for monochrome (2-color) graphics

View File

@ -245,7 +245,7 @@ On the c64 and cx16, the rom routines are used for floating point operations,
so on both systems the correct rom banks have to be banked in to make this work.
Although the C128 shares the same floating point format, Prog8 currently doesn't support
using floating point on that system (because the c128 fp routines require the fp variables
to be in another ram bank than the program, something Prog8 doesn't do).
to be in another ram bank than the program, something Prog8 doesn't support yet).
Also your code needs to import the ``floats`` library to enable floating point support
in the compiler, and to gain access to the floating point routines.
@ -258,6 +258,11 @@ You can use underscores to group digits in floating point literals to make long
any underscores in the number are ignored by the compiler.
For instance ``30_000.999_999`` is a valid floating point number 30000.999999.
.. attention::
On the X16, make sure rom bank 4 is still active before doing floationg point operations (it's the bank that contains the fp routines).
On the C64, you have to make sure the Basic ROM is still banked in (same reason).
.. _arrayvars:
Arrays

View File

@ -3,22 +3,26 @@
%import sorting
%import strings
%zeropage basicsafe
%option no_sysinit
; A "TUI" for an interactive file selector, that scrolls the selection list if it doesn't fit on the screen.
; Returns the name of the selected file. If it is a directory instead, the name will start and end with a slash '/'.
; Depends a lot on diskio routines, and uses the drive set in the diskio.drivenumber variable (usually just 8)
; should case folding be done in diskio already? -> no, it doesn't know if you are in iso mode or not.
; TODO use "@$:=p" instead of filtering manually for only dirs use @$:=d , but that needs a change in diskio...
; TODO is there a way to detect if iso charset mode is active (not really, except read the kernal variable...)
; TODO joystick control? mouse control?
; TODO keyboard typing; jump to the first entry that starts with that character? (but 'q' for quit stops working then)
; TODO keyboard typing; jump to the first entry that starts with that character? (but 'q' for quit stops working then, plus scrolling with pageup/down is already pretty fast)
main {
sub start() {
fileselector.configure(20, 10, 20, true, 2)
txt.iso()
fileselector.configure_settings(true, true, 2)
fileselector.configure_appearance(10, 10, 20, $b3, $d0, true)
uword chosen = fileselector.select("*")
txt.nl()
txt.print_ub(cx16.getrambank())
txt.nl()
if chosen!=0 {
txt.print("chosen: ")
@ -32,27 +36,41 @@ main {
}
fileselector {
%option ignore_unused
const uword filenamesbuffer = $a000 ; use a HIRAM bank
const uword filenamesbuf_size = $1e00 ; leaves room for a 256 entry string pointer table at $be00-$bfff
const uword filename_ptrs_start = $be00 ; array of 256 string pointers for each of the names in the buffer. ends with $0000.
ubyte dialog_topx = 4
ubyte dialog_topx = 10
ubyte dialog_topy = 10
ubyte max_lines = 20
ubyte colors_normal = $b3
ubyte colors_selected = $d0
ubyte buffer_rambank = 1 ; default hiram bank to use for the data buffers
bool also_directories = true
ubyte show_what = 3 ; dirs and files
bool iso_mode = false
ubyte chr_topleft, chr_topright, chr_botleft, chr_botright, chr_horiz, chr_vert, chr_jointleft, chr_jointright
str chosen_filename = "?" * 32
uword name_ptr
ubyte num_visible_files
uword name_ptr
sub configure(ubyte column, ubyte row, ubyte max_entries, bool also_dirs, ubyte rambank) {
sub configure_settings(bool show_files, bool show_dirs, ubyte rambank) {
buffer_rambank = rambank
show_what = 0
if show_files show_what |= 1
if show_dirs show_what |= 2
set_characters(false)
}
sub configure_appearance(ubyte column, ubyte row, ubyte max_entries, ubyte normal, ubyte selected, bool iso_chars) {
dialog_topx = column
dialog_topy = row
max_lines = max_entries
buffer_rambank = rambank
also_directories = also_dirs
colors_normal = normal
colors_selected = selected
iso_mode = iso_chars
}
sub select(str pattern) -> uword {
@ -64,26 +82,35 @@ fileselector {
; pattern = 0 ; force pattern to be 0 instead of empty string, to be compatible with prog8 11.0 or older
num_visible_files = 0
chosen_filename[0] = 0
diskio.list_filename[0] = 0
name_ptr = diskio.diskname()
if name_ptr==0 or cbm.READST()!=0
return 0
txt.cls()
set_characters(iso_mode)
txt.color2(colors_normal & 15, colors_normal>>4)
background(0, 3)
txt.plot(dialog_topx, dialog_topy)
txt.print("┌")
txt.chrout(chr_topleft)
linepart()
txt.print("┐\n")
txt.chrout(chr_topright)
txt.nl()
txt.column(dialog_topx)
txt.print("│ drive ")
txt.chrout(chr_vert)
txt.print(" drive ")
txt.print_ub(diskio.drivenumber)
txt.print(": '")
txt.print(name_ptr)
txt.chrout('\'')
txt.column(dialog_topx+31)
txt.print("│\n")
txt.chrout(chr_vert)
txt.nl()
txt.column(dialog_topx)
txt.print("│ scanning directory... │\n")
txt.chrout(chr_vert)
txt.print(" scanning directory... ")
txt.chrout(chr_vert)
txt.nl()
txt.column(dialog_topx)
footerline()
@ -95,41 +122,56 @@ fileselector {
construct_name_ptr_array()
; sort alphabetically
sorting.shellsort_pointers(filename_ptrs_start, num_files, sorting.string_comparator)
num_visible_files = min(max_lines, num_files)
; initial display
background(5, 3 + num_visible_files -1)
txt.plot(dialog_topx+2, dialog_topy+2)
txt.print("select file: (")
txt.print("select ")
if show_what & 1 == 1
txt.print("file")
else
txt.print("directory")
txt.print(": (")
txt.print_ub(num_files)
txt.print(" total)")
txt.column(dialog_topx+31)
txt.print("│\n")
txt.chrout(chr_vert)
txt.nl()
txt.column(dialog_topx)
txt.print("│ stop or q to abort |\n")
txt.chrout(chr_vert)
txt.print(" stop or q to abort ")
txt.chrout(chr_vert)
txt.nl()
txt.column(dialog_topx)
txt.print("├")
txt.chrout(chr_jointleft)
linepart()
txt.print("┤\n")
txt.chrout(chr_jointright)
txt.nl()
print_up_indicator(false)
if num_files>0 {
for selected_line in 0 to min(max_lines, num_files)-1 {
for selected_line in 0 to num_visible_files-1 {
txt.column(dialog_topx)
txt.print("│ ")
txt.chrout(chr_vert)
txt.spc()
print_filename(peekw(filename_ptrs_start+selected_line*$0002))
txt.column(dialog_topx+31)
txt.print("│\n")
num_visible_files++
txt.chrout(chr_vert)
txt.nl()
}
} else {
txt.column(dialog_topx)
txt.print("│ no matches.")
txt.chrout(chr_vert)
txt.print(" no matches.")
txt.column(dialog_topx+31)
txt.print("│\n")
txt.chrout(chr_vert)
txt.nl()
}
print_down_indicator(false)
txt.column(dialog_topx)
footerline()
selected_line = 0
invert(selected_line)
select_line(0)
print_up_and_down()
repeat {
@ -141,49 +183,49 @@ fileselector {
3, 27, 'q' -> return 0 ; STOP or Q aborts (and ESC?)
'\n',' ' -> {
if num_files>0 {
void strings.copy(peekw(filename_ptrs_start + (top_index+selected_line)*$0002), chosen_filename)
return chosen_filename
void strings.copy(peekw(filename_ptrs_start + (top_index+selected_line)*$0002), &diskio.list_filename)
return diskio.list_filename
}
return 0
}
'[',130,157 -> { ; PAGEUP, cursor left
; previous page of lines
invert(selected_line)
unselect_line(selected_line)
if selected_line==0
repeat max_lines scroll_list_backward()
selected_line = 0
invert(selected_line)
select_line(0)
print_up_and_down()
}
']',2,29 -> { ; PAGEDOWN, cursor right
if num_files>0 {
; next page of lines
invert(selected_line)
unselect_line(selected_line)
if selected_line == max_lines-1
repeat max_lines scroll_list_forward()
selected_line = num_visible_files-1
invert(selected_line)
select_line(selected_line)
print_up_and_down()
}
}
17 -> { ; down
if num_files>0 {
invert(selected_line)
unselect_line(selected_line)
if selected_line<num_visible_files-1
selected_line++
else if num_files>max_lines
scroll_list_forward()
invert(selected_line)
select_line(selected_line)
print_up_and_down()
}
}
145 -> { ; up
invert(selected_line)
unselect_line(selected_line)
if selected_line>0
selected_line--
else if num_files>max_lines
scroll_list_backward()
invert(selected_line)
select_line(selected_line)
print_up_and_down()
}
}
@ -196,8 +238,14 @@ fileselector {
name_ptr = filenamesbuffer
repeat num_files {
pokew(filename_ptrs, name_ptr)
while @(name_ptr)!=0
name_ptr++
if iso_mode {
; no case folding in iso mode
while @(name_ptr)!=0
name_ptr++
} else {
; case-folding to avoid petscii shifted characters coming out as symbols TODO should diskio do this already?
name_ptr += strings.lower(name_ptr)
}
name_ptr++
filename_ptrs+=2
}
@ -268,43 +316,88 @@ fileselector {
sub print_up_indicator(bool shown) {
txt.plot(dialog_topx, dialog_topy+5)
txt.chrout('│')
txt.chrout(chr_vert)
txt.column(dialog_topx+26)
if shown
txt.print("(up) │\n")
txt.print("(up)")
else
txt.print(" │\n")
txt.print(" ")
txt.spc()
txt.chrout(chr_vert)
txt.nl()
}
sub print_down_indicator(bool shown) {
txt.plot(dialog_topx, dialog_topy+6+num_visible_files)
txt.chrout('│')
txt.chrout(chr_vert)
txt.column(dialog_topx+24)
if shown
txt.print("(down) │\n")
txt.print("(down)")
else
txt.print(" │\n")
txt.print(" ")
txt.spc()
txt.chrout(chr_vert)
txt.nl()
}
sub footerline() {
txt.chrout('└')
txt.chrout(chr_botleft)
linepart()
txt.chrout('┘')
txt.chrout(chr_botright)
}
sub linepart() {
repeat 30 txt.chrout('─')
repeat 30 txt.chrout(chr_horiz)
}
sub invert(ubyte line) {
sub select_line(ubyte line) {
line_color(line, colors_selected)
}
sub unselect_line(ubyte line) {
line_color(line, colors_normal)
}
sub line_color(ubyte line, ubyte colors) {
cx16.r1L = dialog_topy+6+line
ubyte charpos
for charpos in dialog_topx+1 to dialog_topx+30 {
txt.setchr(charpos, cx16.r1L, txt.getchr(charpos, cx16.r1L) ^ 128)
txt.setclr(charpos, cx16.r1L, colors)
}
}
}
sub set_characters(bool iso_chars) {
if iso_chars {
chr_topleft = iso:'í'
chr_topright = iso:'ì'
chr_botleft = iso:'`'
chr_botright = iso:'\''
chr_jointleft = chr_jointright = iso:':'
chr_vert = iso:'|'
chr_horiz = iso:'-'
} else {
chr_topleft = '┌'
chr_topright = '┐'
chr_botleft = '└'
chr_botright = '┘'
chr_horiz = '─'
chr_vert = '│'
chr_jointleft = '├'
chr_jointright = '┤'
}
}
sub background(ubyte startrow, ubyte numlines) {
startrow += dialog_topy
repeat numlines {
txt.plot(dialog_topx+1, startrow)
repeat 30 txt.chrout(' ')
txt.nl()
startrow++
}
}
sub get_filenames(uword pattern_ptr, uword filenames_buffer, uword filenames_buf_size) -> ubyte {
uword buffer_start = filenames_buffer
ubyte files_found = 0
@ -312,9 +405,11 @@ fileselector {
if diskio.lf_start_list(pattern_ptr) {
while diskio.lf_next_entry() {
bool is_dir = diskio.list_filetype=="dir"
if is_dir and show_what & 2 == 0
continue
if not is_dir and show_what & 1 == 0
continue
if is_dir {
if not also_directories
continue
@(filenames_buffer) = '/' ; directories start with a slash so they're grouped when sorting
filenames_buffer++
}