Jump to content

Recommended Posts

I have  started developing the VERA Text User Interface Library (vtuilib) and could use a little help for ideas and suggestions.

My plan is to create 3 different flavors of the library:

  • Include file for the ACME assembler
  • Include file for the CA65 assembler
  • Binary library file that can be loaded with any program

So far the library is still in very early development and there is no documentation yet, but I have implemented a few basic functions such as set_stride, set_decr, print_str and line drawing functions in the generic library.

There will of course be functions to draw boxes, filled and not filled as well as functions to save and restore a certain area of screen. 

The binary library is designed to function in any memory location so depending on the final size, it might be possible to load it to "golden" RAM at $0400 which is what I am doing so far. Another approach is to design it to live in banked memory.

What are your thoughts?

How important is it that the binary library can be located anywhere in RAM?

Which functions would you like to see?

Anything I have missed?

  • Like 4

Share this post


Link to post
Share on other sites
  • I assume it will have text output in some form (to place text at specific position). It would be nice if it has routines for both screencode and  PETSCII encoding
  • box drawing/filling with or without a certain border (and optional "pane" title perhaps)
  • clear screen
  • setting background and foreground color
  • scrolling a rectangle up by 1 character 
  • perhaps also scrolling a rectangle down,left,right by 1 character ?
  • plotting a single character at x,y ?
  • getting a single character at x,y ?
  • reading a user inputted string from the keyboard (where the input is constrained by certain width to not clobber the screen outside of a certain rectangle/pane) ?
  • perhaps a bit of a stretch: word-wrapped text output within a rectangle
  • don't burden the library with things such as number to text conversion routines

(Prog8's textio library has some of these routines already but those operate full-screen)

Share this post


Link to post
Share on other sites

@desertfish Thank you very much for your suggestions.

29 minutes ago, desertfish said:

It would be nice if it has routines for both screencode and  PETSCII encoding

That is a very good idea, I had not thought of that 🙂

31 minutes ago, desertfish said:

scrolling a rectangle up by 1 character 

I am not sure I understand... Do you want to be able to move the entire rectangle or do you want to scroll inside a rectangle?

Share this post


Link to post
Share on other sites
4 hours ago, desertfish said:
  • I don't burden the library with things such as number to text conversion routines

Curious about this one. I had to do that very thing yesterday and while it ended up being reasonably simple, for someone new to ASM having something ready made would avoid unnecessary speed bumps. I didn't get nearly as much done yesterday on my actual application due to having to write something like that.

The other suggestions make a lot of sense and are also things I've had to implement on my own where having something ready-made would have been useful. In fact should anyone want to peruse those, they are here:

https://gitlab.com/m00dawg/command-tracker/-/tree/master/library/graphics

I tried to make those reasonably generic (whereas my app specific stuff is under library/ui). If you want to use them, noting the license (GPLv3), feel free!

  • Like 1

Share this post


Link to post
Share on other sites

I managed to create the initialization function that ensures the generic library can be loaded into any address and still function as expected.

Self-modifying code makes my brain hurt so I might not get much else done today.

If you want, feel free to take at look at https://github.com/jimmydansbo/vtuilib/

There is still no documentation other than comments in code and the vtuitest.asm shows how to load the generic library.

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites
1 hour ago, m00dawg said:

Curious about this one.

I was thinking: number to text conversion is very application specific (decimal? with or without prefix zeros or spacing?  hex/binary perhaps? with or without radix prefix $/% ?  left aligned/right aligned? signed or unsinged?  bytes or words or perhaps even bigger?) so just let the application do it and only deal with strings in this library. 

Share this post


Link to post
Share on other sites

Those are good points. Still, a sort of basic one (unsigned integer) with no formatting might be helpful for new folk. Having to write basic I/O before one can even write programs to experiment around is, to me, an unnecessary hurdle which could be scaring away otherwise awesome programmers that could make great games and things.

But yeah I think apart from something very simple, you bring up a good point. My code, for instance, often accounts for the color of the text as part of the routine. Often times I just use one of the ZP 'r' registers (like r0) to pass that through to the end procedure that ends up doing the actual output. But that could be quite different for various folks.

Maybe instead of full output, a helper function to convert to/from screencodes would be nice. Realizing screencodes != petscii codes was like stepping on a rake for me.

Share this post


Link to post
Share on other sites

I agree, some basic number output should be included. Even if it's just one byte to a decimal number between 0 and 255. Everything else could be done by a user conversion function that turns data into strings.

@JimmyDansbo do you plan to make the UI work with the mouse? Or via keyboard? Or do you just want to provide drawing routines and let the user program handle the interactive part?

  • Like 1

Share this post


Link to post
Share on other sites

@kliepatsch Yes, a /10 with remainder function, and then an unsigned integer to number string function built from that would be useful, as would scr2p and p2scr.

The second pair would be particularly helpful to experienced 6502 assembly programmers who are not used to the oddities of both PETSCII and Commodore screencodes.

Edited by BruceMcF

Share this post


Link to post
Share on other sites
1 hour ago, kliepatsch said:

do you plan to make the UI work with the mouse? Or via keyboard? Or do you just want to provide drawing routines and let the user program handle the interactive part?

My plan was to just provide the drawing routines and let the user handle everything else. I do plan to provide a function that can preserve a window so it can be restored late, effectively allowing for popup windows or message boxes.

48 minutes ago, BruceMcF said:

as would scr2p and p2scr.

The second pair would be particularly helpful to experienced 6502 assembly programmers who are not used to the oddities of both PETSCII and Commodore screencodes

I was thinking of having functions that output strings only accept petscii and then convert it to screen codes. Functions that output/use single character will require screencodes, and then provide a couple of very basic functions for converting to/from screen-/petscii-codes.

I am hoping to be able to keep the size of the generic library within 2K so it can be loaded into "golden" RAM. We will see, it might ned a memory bank for it self in the end.

For now it is just under 400 bytes, but not at all complete yet.

  • Like 1

Share this post


Link to post
Share on other sites
1 minute ago, BruceMcF said:

Golden RAM is $0400 to $07FF, which is 1K

You are right, even greater risk it will not fit in golden RAM.

Share this post


Link to post
Share on other sites

@JimmyDansbo A nice size to aim for with high RAM segment libraries if they do not require 8K is 4K, then you can make two binaries, one for $A000-$AFFF and another for $B000-$BFFF. Similarly 4 binaries with a 2K high RAM segment library.

  • Like 1

Share this post


Link to post
Share on other sites

Another way of adding the generic library would be to add it as a binary at the end of users own source.

For ACME, this can be done with the !BIN statement. Do anyone know if the same is possible with other assemblers?

Share this post


Link to post
Share on other sites

It's probably for the best to just make it relocatable rather than forcing developers to put it in any particular part of memory. ca65 is really good at letting you do this.

  • Like 1

Share this post


Link to post
Share on other sites

I have already made it relocatable. It does not care what address it is loaded at. All that is needed is to initialize the library by JSR'ing to the base address after load.

If you have loaded the library to $0400, you just JSR $0400 or if you have loaded it to $A400, you JSR $A400.

Afterwards the functions are callable by BASEADDR+2, BASEADDR+5, BASEADDR+8, BASEADDR+11 and so on.

  • Like 1

Share this post


Link to post
Share on other sites
11 hours ago, desertfish said:
  • I assume it will have text output in some form (to place text at specific position). It would be nice if it has routines for both screencode and  PETSCII encoding
  • box drawing/filling with or without a certain border (and optional "pane" title perhaps)
  • clear screen
  • setting background and foreground color

+1 on those.

 

11 hours ago, desertfish said:
  • scrolling a rectangle up by 1 character 
  • perhaps also scrolling a rectangle down,left,right by 1 character ?

I was thinking, the library could provide a "wrapper" to make easy use of the two text layers, e.g. to be able to easily scroll text in a text field (only one at a time, of course) or something. But I don't know how well that fits with a "compact library" idea 😉

11 hours ago, desertfish said:

reading a user inputted string from the keyboard (where the input is constrained by certain width to not clobber the screen outside of a certain rectangle/pane) ?

+1 on that, too. This can be an annoying task, especially for beginners like me, and it is great to have a ready-made tool for string input. And I think this wouldn't be too large of a function.

BTW I'll just give a brief overview on how a few aspects of the UI that I made (not claiming that one should do so ... just to give a few extra ideas into the mix)

  • I used display lists. That is, lists with information about where to draw what element, that could be processed by a drawing routine.
    • One list with "labels". It contained I think 5 bytes for each entry. The color, the X and Y coordinates and the 16 bit pointer to a zero-terminated string. The end of the list would simply be marked with a 0 as the next color (which would be black foreground and black background, thus safe to assume that no one uses that). There is a routine that draws all of them in one go.
    • One list with control elements such as buttons, checkboxes, drop-down menus and so on. The amount of bytes occupied by each control element differs. Point is, all data necessary for drawing them is in one single list, and there is a routine that draws all GUI control elements in one go. (But control elements can still be redrawn individually if needed)
       
    • This approach is quite memory efficient in terms of size necessary to store the actual UI. The code can become messy. But I think this might be the case for any UI in machine language. (Haven't looked at the source of GEOS in detail though, I have to admit)
  • I organized the whole UI in "panels". They are basically rectangular areas containing stuff. E.g. each panel has its own "labels" and "control elements" display lists. There were several benefits from that. Most importantly:
    • Display lists can be kept shorter than 256 bytes for efficient processing. (If a panel contains too much stuff, simply divide the panel into two to shorten the display lists. Didn't happen for me.)
    • Panels could be activated and ordered. A number is assigned to each panel. There is a list of active panels (think of it as a "stack"). A panel appearing further up in the stack is drawn later, so it appears on top of the other panels. And it is checked first for mouse-overs (because it is on top ...). That's how my drop-down menus work. Basically a panel gets activated and deactivated when operating them. Other pop-ups can easily be done in a similar way.
    • It is easily possible to swap out parts of the UI or even the entire UI just by putting a set of different numbers into the "panel stack". Didn't make use of this yet.
    • Panels speed up the process of recognizing what the mouse is currently pointing at. They subdivide the whole UI into groups, so you don't always have to check each and every control element for mouse-over.

Share this post


Link to post
Share on other sites

Great initiative Jimmy. I think we all wrote bits and pieces of these type of routines but it would be great to have a library at our disposal.

 

Share this post


Link to post
Share on other sites

When I was working on something reusable for my needs I was always struggling with really how generic such a library can and should be. I can think of few dilemmas from the top of my head:

Do I support default screen size only or make it generic, specifically Map width is tricky one because if you want to support anything else than 128 tile width the VERA MID parameter is no longer Y dimension and require more checks and bit shifting.

How to handle colors, do I go for standard predefined colors for different objects/widgets or should they always be passed as parameters. If second what happens if you want to draw e.g. frame parts in different colors to represent highlights etc.

Do I allow different variations e.g. can frame be with rounded corners or square corners or perhaps the whole frame can be built with full or half blocks or even custom characters.

Support for Lower case / Upper case PETSCI / ISO and then translations to screen codes

Before mentioned number to text translations

etc.

 

This can lead to a real rabbit hole of options so I suggest not to overthink and to really simplify the first version and only support default screen and very basic functionality and then see where it leads.

  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

I have come a bit further. The generic library is functional although it does not have too many functions yet.

I spent all of the evening yesterday trying to write some documentation and hopefully it is understandable.

Have a look at https://github.com/JimmyDansbo/vtuilib/blob/main/VTUIlib-generic.md

You can also look at the examples and download the binary here: https://github.com/JimmyDansbo/vtuilib/tree/main/VTUIlib-generic

The example shows off most of the functions currently implemented and should look like this:

image.thumb.png.0fd101480e19a3664aeb94f4c7a689ed.png

Let me know if anything is unclear ( there are probably things that needs to be rewritten or clarified)

  • Like 4
  • Thanks 1

Share this post


Link to post
Share on other sites
3 hours ago, JimmyDansbo said:

I have come a bit further. The generic library is functional although it does not have too many functions yet.

I spent all of the evening yesterday trying to write some documentation and hopefully it is understandable.

Have a look at https://github.com/JimmyDansbo/vtuilib/blob/main/VTUIlib-generic.md

You can also look at the examples and download the binary here: https://github.com/JimmyDansbo/vtuilib/tree/main/VTUIlib-generic

The example shows off most of the functions currently implemented and should look like this:

image.thumb.png.0fd101480e19a3664aeb94f4c7a689ed.png

Let me know if anything is unclear ( there are probably things that needs to be rewritten or clarified)

This is looking nice 👌 

Share this post


Link to post
Share on other sites

I think I have reached a point where I have the Generic VTUI light-library finished. I have managed to fit the functions I initially wanted into 1KB so it can be loaded into golden RAM.

The functions included are:

  • initialize - Initialize the jumptable at the beginning of the library to make it easy to call the rest of the functions
  • screen_set - Set the screen to 40x30 or 80x60 or toggle between the two
  • clear - Clear the screen with a specified color
  • set_stride - Set the VERA stride value
  • set_decr - Set or reset the VERA decrement bit
  • gotoxy - Point VERA memory to specific coordinates on screen
  • plot_char - Put a screencode character and color code on screen at the current VERA address
  • scan_char - Read a screencode character and color code from screen at current VERA address
  • hline - Draw a horizontal line
  • vline - Draw a vertical line
  • print_str - Convert and print a 0-terminated PETSCII string to screen at current VERA address
  • fill_box - Create a filled box
  • pet2scr - Convert a PETSCII code to screencode
  • scr2pet - Convert a screencode to PETSCII
  • border - Draw a non-filled box with a border
  • save_rect - Save an area from screen to memory
  • rest_rect - Restore screen from memory

I know that this is very basic, but hopefully it could, at least, help people get an understanding on how these things could work. I still have lots of work to do as I have not done anything on the ACME and CA65 include files. I also need to create another example and possibly a demo of how to use the library.

I think I will leave the light version with the above functions, and focus on getting the include files finished as well as create a demo on how to use the library.

I do plan on extending the library with scrolling, string input, hex/number to string conversion and more, but for now I will get this light version finished.

  • Like 6

Share this post


Link to post
Share on other sites

This is great yep! I have a lot my own routines that do the same thing in my program at moment, however, I would like to test your library against my current solution at some point soon since I think having a standard TUI library between apps would be great! (Maybe a suitable use of ROM in the future!?).

I noticed from your screenshots that your lines connected with the outer box border. Is that "automatic" or how did you end up doing that? My current routines draw all the boxes and lines and then I go back and add the connectors after, which has resulted in a few visual bugs when I switch to different panes on my app (as I intentionally don't want to redraw the whole screen when I switch). Hopefully that makes sense!

  • Like 1

Share this post


Link to post
Share on other sites
1 hour ago, m00dawg said:

I noticed from your screenshots that your lines connected with the outer box border. Is that "automatic" or how did you end up doing that?

It is not automatic, neither is the header of a box.

I just draw a border and a fill_box, then I use plot_char to replace the border with T-pieces where necessary, use print_str to write the header and and hline to draw a horizontal line across my box.

In a more feature-rich library there would be the option to add headers to boxes and to divide a box with horizontal or vertical lines. As it is now, the user has to use the basic functions provided to create those advanced features.

Edited by JimmyDansbo
made VTUI library function names bold
  • Like 1
  • Thanks 1

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.


×
×
  • Create New...

Important Information

Please review our Terms of Use