Hello everyone,
I'm trying to put together a TUI framework, I've been looking at other TUI projects and there is much variation in what they provide. I want to create my own for use with the Pico but I want to have the same code usable on the pi as well. I have a working framework already with abstraction layer so that I can output to a VT100 compatible console or switch that out for my PT52 project.
The big question I have is what makes it a TUI? At first I thought it was like a GUI with widgets and windows, then a lot of project just give the most basic screen control. I'm sure it's all down to what you as the programmer wants and needs.
What I have done is gone with the KISS version of the TUI I took what I thought were the best features from the simpler projects and wrote code for that.
I have a buffer that is updated behind the display and then refreshed all at once. I have the capability to write to any place in the buffer as a single character or a formatted string. To keep it simple there is no line wrap all commands are sent as Escape codes, obviously for input on a native Linux console I have to use some additional configurations but mostly that's it all it can do. Does that make it a TUI? if not what's missing?
-
- Posts: 2556
- Joined: Tue Mar 20, 2018 9:53 pm
Re: What makes it a TUI?
tui = text user interface
basically runs in console with out the need for X
console file managers are tui, i use nnn.
basically runs in console with out the need for X
console file managers are tui, i use nnn.
- Attachments
-
- 2023-01-21-163454_1280x720_scrot.png (129.98 KiB) Viewed 2124 times
Re: What makes it a TUI?
I have used Dialog in Linux for a TUI.
Midnight Commander is my default TUI File manager.
Midnight Commander is my default TUI File manager.
I'm dancing on Rainbows.
Raspberries are not Apples or Oranges
Raspberries are not Apples or Oranges
-
- Posts: 581
- Joined: Sun Dec 03, 2017 1:47 am
- Location: Boston area, MA, USA
Re: What makes it a TUI?
To my mind, a TUI is a GUI that uses a character cell display model. I don't think I care about the implementation details.
I use a terminal emulator that supports images, and have simple keyboard+SVG GUIs that I think fail "the TUI test". Conversely opening a window via X or Wayland doesn't mean it's not a TUI - if it renders only a character cell grid, it might be said to "integrate a terminal emulator".
I use a terminal emulator that supports images, and have simple keyboard+SVG GUIs that I think fail "the TUI test". Conversely opening a window via X or Wayland doesn't mean it's not a TUI - if it renders only a character cell grid, it might be said to "integrate a terminal emulator".
Re: What makes it a TUI?
Faking a GUI with TUI
https://en.wikipedia.org/wiki/DOS_Shell
Makes use of those Ascii line characters.
Midnight commander is very useful for headless Linux installs.

https://en.wikipedia.org/wiki/DOS_Shell
Makes use of those Ascii line characters.
Midnight commander is very useful for headless Linux installs.
I'm dancing on Rainbows.
Raspberries are not Apples or Oranges
Raspberries are not Apples or Oranges
Re: What makes it a TUI?
This sort of thing is normally done with curses which is very capable and easy to use.DarkElvenAngel wrote: ↑Sun Jan 22, 2023 2:23 amWhat I have done is gone with the KISS version of the TUI I took what I thought were the best features from the simpler projects and wrote code for that.
I have a buffer that is updated behind the display and then refreshed all at once. I have the capability to write to any place in the buffer as a single character or a formatted string. To keep it simple there is no line wrap all commands are sent as Escape codes, obviously for input on a native Linux console I have to use some additional configurations but mostly that's it all it can do.
The library is always included on Linux and UNIX systems (and elsewhere).
To get the header file and the man pages:
Code: Select all
sudo apt install ncurses-dev ncurses-doc
-
- Posts: 581
- Joined: Sun Dec 03, 2017 1:47 am
- Location: Boston area, MA, USA
Re: What makes it a TUI?
I haven't learned curses and a search found this: "From a C programmer’s point of view, curses may sometimes look like a twisty maze of functions, all subtly different" here https://docs.python.org/3/howto/curses.html.

I also learned ncurses doesn't support 24 bit color (https://invisible-island.net/ncurses/nc ... MegaColors) which I use a great deal. I'm prototyping in Python and my "Stylin'" string class supports 24 bit color - subtle color choices are a great source of enjoyment and procrastination.
My code is just for me and I'm entirely solipsistic: "well, it works when I run it". If you have altruistic goals like making something useful, YMMV.
Re: What makes it a TUI?
Without boxes and wrapping/scrolling it would be somewhat limited as a general purpose tui.
-
- Posts: 581
- Joined: Sun Dec 03, 2017 1:47 am
- Location: Boston area, MA, USA
Re: What makes it a TUI?
Personally, what I think what you have is a "character display emulation layer" (and a formatted string type, it sounds like).DarkElvenAngel wrote: ↑Sun Jan 22, 2023 2:23 amI have a buffer that is updated behind the display and then refreshed all at once. I have the capability to write to any place in the buffer as a single character or a formatted string. To keep it simple there is no line wrap all commands are sent as Escape codes, obviously for input on a native Linux console I have to use some additional configurations but mostly that's it all it can do. Does that make it a TUI? if not what's missing?
A "TUI Toolkit" could use this as a backend.
Re: What makes it a TUI?
Curses has boxes, windows, pads etc (pads are windows that are not limited by screen size).
And obviously it has scrolling, that's basic. You may scroll the text inside a window or pad too.
Not sure about automatic text wrapping, I never needed it, but vi and others do it. Maybe by hand, I don't know.
Curses does a lot of optimization (for example it works out the minimal set of changes before updating the screen) which I suspect is pointless in this day and age!
-
- Posts: 2556
- Joined: Tue Mar 20, 2018 9:53 pm
Re: What makes it a TUI?
Thank you for all the replies,
ncurses is great for native linux application I've used it a few times, I don't know that it would be portable to the Pico I haven't look into it really. I have looked at the source code for vi and another where it walks through all the code and from that these editors basically put together there own TUI interface. Where something like nano uses ncurses.
I've got input processing working now, I can see where using ncursers and others is a huge advantage here, decoding the incoming key stroke from the raw escape codes I've only got the basics covered. these limitations would be present over a serial terminal so I'll call it good enough.
My goal in all this is to make writing configuration screens and status displays easy and portable between my three platforms. It would be handy if I can write simple applications for use over USB Serial or native on the PT52 (My Pico serial terminal project)
ncurses is great for native linux application I've used it a few times, I don't know that it would be portable to the Pico I haven't look into it really. I have looked at the source code for vi and another where it walks through all the code and from that these editors basically put together there own TUI interface. Where something like nano uses ncurses.
Okay so if the backend is there and I need a toolkit are there some examples of simple toolkits?Daniel Gessel wrote:Personally, what I think what you have is a "character display emulation layer" (and a formatted string type, it sounds like).DarkElvenAngel wrote: ↑Sun Jan 22, 2023 2:23 amI have a buffer that is updated behind the display and then refreshed all at once. I have the capability to write to any place in the buffer as a single character or a formatted string. To keep it simple there is no line wrap all commands are sent as Escape codes, obviously for input on a native Linux console I have to use some additional configurations but mostly that's it all it can do. Does that make it a TUI? if not what's missing?
A "TUI Toolkit" could use this as a backend.
I've got input processing working now, I can see where using ncursers and others is a huge advantage here, decoding the incoming key stroke from the raw escape codes I've only got the basics covered. these limitations would be present over a serial terminal so I'll call it good enough.
My goal in all this is to make writing configuration screens and status displays easy and portable between my three platforms. It would be handy if I can write simple applications for use over USB Serial or native on the PT52 (My Pico serial terminal project)
Re: What makes it a TUI?
termbox2 might be a candidate as it only has libc as a dependency and its source is basically in one file (which might or might not be a good thing) https://github.com/termbox/termbox2
-
- Posts: 581
- Joined: Sun Dec 03, 2017 1:47 am
- Location: Boston area, MA, USA
Re: What makes it a TUI?
You may not benefit from a toolkit if you only need to support simple configuration menus and a few other features (or maybe it's a mini-toolkit?)
But termbox2 does look pretty useful - I like that interactive tree demo (there's a link to it in the readme) - I might grab it!
But termbox2 does look pretty useful - I like that interactive tree demo (there's a link to it in the readme) - I might grab it!
-
- Posts: 2556
- Joined: Tue Mar 20, 2018 9:53 pm
Re: What makes it a TUI?
Thanks, I was looking at the original Termbox that is no longer maintained. Other than the colour support the API is about what I have now ...pidd wrote: ↑Mon Jan 23, 2023 12:02 amtermbox2 might be a candidate as it only has libc as a dependency and its source is basically in one file (which might or might not be a good thing) https://github.com/termbox/termbox2
Code: Select all
void tui_init();
void tui_end();
void tui_clean();
void tui_get_size(int8_t *rows, int8_t *cols);
void tui_paint();
void tui_set_cursor(bool visible);
void tui_set_char(uint8_t row, uint8_t col, char c);
void tui_printf(uint8_t row, uint8_t col, char *format, ...);
int tui_get_keypress();
I'm thinking your right a minitool kit that has some common elements, these could be included if desired or left out. The termbox2 keyboard demo is completely done with no tool kit at all it's an impressive demo. I will be adding that to my list of useful tools as well.Daniel Gessel wrote: You may not benefit from a toolkit if you only need to support simple configuration menus and a few other features (or maybe it's a mini-toolkit?)
But termbox2 does look pretty useful - I like that interactive tree demo (there's a link to it in the readme) - I might grab it!
Re: What makes it a TUI?
This is one of those problems where you need to decide in advance what it needs to be capable of and importantly, not exceed it.
I cobbled together a really rudimentary console output for the pico in that it's an lcd display but that doesn't matter too much. I don't know (haven't checked) if I can read from the lcd and there's not enough ram for anything fancy like a frame buffer. Essentially, when the device is initialised, you need the pixel dimensions of the lcd and the cell size of the monospaced font which will be used. It then creates a character buffer. Nothing goes to the lcd by default: characters are manipulated in the buffer. It takes a specific "refresh" call to send something to the lcd.
Note that line wrapping can be avoided if you treat the character buffer as a 1d array rather than a 2d one. All you need do is increment the "cursor" until it hits the end of the buffer. You get line wrapping for free.
I was also minded to create a "cursor" object (this is all in crude C++) which is handy for manipulating the cursor and would be a useful block should multiple "processes" want to draw.
No colours or anything atm. If I were to do that I'd consider using the same character/cursor logic for implementing colour. Just add a second 1d array for the foreground colours and a third 1d array for background if desired - or possibly just a single 1d array with fg/bg in each nibble: 16 colours is probably enough. Use a palette to reference the actual colour. Additionally it cannot scroll. Sure you can scroll the buffer but it is going to require a redraw of the entire lcd for each line which is where the bottleneck will lie so this is where you need to test - assuming you even need vertical scrolling.
I've mentioned GEM (the Atari ST GUI) before in an older post. Dunno why. It's underlying pixel system had two(*) modes. A normal "plot x,y" and a second character based mode. This second mode may be worth consideration. Rather than drawing objects at x,y it performed a draw at cell position cx+ox,cy+oy in that cx,cy were cell co-ordinates and ox,oy were pixel offsets from cx,cy.
(*) Atari only implemented pixel mode but the point still stands.
..thus, you could have mapped (eg: windowed ncurses) onto a cell device (eg: dot matrix printer) or a pixel device. The cell device would ignore ox,oy whereas the pixel device would have used cx+ox,cy+oy to place the object precisely. It also had a very efficient tree for defining its graphical objects. An array of OBJECT (a C struct) with the root node at index[0]. No actual pointers - they were simple array indices. Whilst there were calls to do things like make a button selected etc the design was such that you could simply manipulate a bit in an OBJECT field (eg: to toggle a button state). Like the console description above it would do nothing until told to "refresh" whereupon it would walk (possibly) the (entire) tree and draw anything within a clipping rectangle.
In effect, both the TUI and the GUI are the same in this context. Both exist outside of the display device.
I cobbled together a really rudimentary console output for the pico in that it's an lcd display but that doesn't matter too much. I don't know (haven't checked) if I can read from the lcd and there's not enough ram for anything fancy like a frame buffer. Essentially, when the device is initialised, you need the pixel dimensions of the lcd and the cell size of the monospaced font which will be used. It then creates a character buffer. Nothing goes to the lcd by default: characters are manipulated in the buffer. It takes a specific "refresh" call to send something to the lcd.
Note that line wrapping can be avoided if you treat the character buffer as a 1d array rather than a 2d one. All you need do is increment the "cursor" until it hits the end of the buffer. You get line wrapping for free.

No colours or anything atm. If I were to do that I'd consider using the same character/cursor logic for implementing colour. Just add a second 1d array for the foreground colours and a third 1d array for background if desired - or possibly just a single 1d array with fg/bg in each nibble: 16 colours is probably enough. Use a palette to reference the actual colour. Additionally it cannot scroll. Sure you can scroll the buffer but it is going to require a redraw of the entire lcd for each line which is where the bottleneck will lie so this is where you need to test - assuming you even need vertical scrolling.
I've mentioned GEM (the Atari ST GUI) before in an older post. Dunno why. It's underlying pixel system had two(*) modes. A normal "plot x,y" and a second character based mode. This second mode may be worth consideration. Rather than drawing objects at x,y it performed a draw at cell position cx+ox,cy+oy in that cx,cy were cell co-ordinates and ox,oy were pixel offsets from cx,cy.
(*) Atari only implemented pixel mode but the point still stands.
..thus, you could have mapped (eg: windowed ncurses) onto a cell device (eg: dot matrix printer) or a pixel device. The cell device would ignore ox,oy whereas the pixel device would have used cx+ox,cy+oy to place the object precisely. It also had a very efficient tree for defining its graphical objects. An array of OBJECT (a C struct) with the root node at index[0]. No actual pointers - they were simple array indices. Whilst there were calls to do things like make a button selected etc the design was such that you could simply manipulate a bit in an OBJECT field (eg: to toggle a button state). Like the console description above it would do nothing until told to "refresh" whereupon it would walk (possibly) the (entire) tree and draw anything within a clipping rectangle.
In effect, both the TUI and the GUI are the same in this context. Both exist outside of the display device.
-
- Posts: 2556
- Joined: Tue Mar 20, 2018 9:53 pm
Re: What makes it a TUI?
I agree that feature creep can be a problem and I've decided to keep everything as simple as possible. To that end I've added the header and footer bars that can exist outside the main display on the PT52. I think the toolkit isn't necessary I can already create menus and such without one so it's not really useful.
I have the header and footer these are addressed outside the normal text buffer and don't support colour or other formatting. They are coloured differently from the rest to show the difference.
I'm using a 2D array for the text buffer, I chose this because the PT52 uses a 2D array. As for colour and attributes I haven't added them to the TUI yet I'm thinking the easiest way will be again to copy the PT52 and use a structure with colour attributes and character for each cell. On the PT52 this can just be copied to the output buffer, for Linux and serial I'm not sure that will be the same. I'm still thinking on that one.
Colour is a hard one since serial can support none of 8 colours, The Linux terminal typically 16 and sometimes 256, The PT52 can also support up to 256 colours. For now though no colour.
I'm work with pure C no fancy C++ classes and such.
I have the header and footer these are addressed outside the normal text buffer and don't support colour or other formatting. They are coloured differently from the rest to show the difference.
I'm using a 2D array for the text buffer, I chose this because the PT52 uses a 2D array. As for colour and attributes I haven't added them to the TUI yet I'm thinking the easiest way will be again to copy the PT52 and use a structure with colour attributes and character for each cell. On the PT52 this can just be copied to the output buffer, for Linux and serial I'm not sure that will be the same. I'm still thinking on that one.
Colour is a hard one since serial can support none of 8 colours, The Linux terminal typically 16 and sometimes 256, The PT52 can also support up to 256 colours. For now though no colour.
I'm work with pure C no fancy C++ classes and such.