Creating a terminal application - 3 - Frontend take 1

Software developmentProjects
  |  

Creating a terminal application - Frontend take 1

Intro

The last post has been a while back. Sorry for that. I was busy with daily business and also the implementation of the terminal got a bit stuck. Now I’m back on track and can feed you with the latest development news.

The backend is only half way towards a complete terminal application. In fact it’s more 1/5 of the way.
The reason to use a terminal application other than the built in one is only its user interface. At least for normal operating systems where the built in terminal works as expected.

So it’s all about user interface and functionality.

As already mentioned I want to take the C# + QML route as it is a good way to dog food Qml.Net and also gain some more QML / Qt insights that help me with my day job. Win-Win 😁

QML might not be the first choice when you need a UI that basically renders its main content all the time and also needs to be fairly fast in doing so. We don’t want to hold back the process we control with having it waiting for our UI to render.

Options

During the backend development I used a very simple QML UI. Basically a Label that got the whole text set whenever the terminal content updated. Performance was OK.
The problem starts with formatting the text. Terminals can have colors, text ranges can be bold or italic.
In any UI devkit I came across (Ok, leave out some of the embedded UI kits) there was a way to define text format for a subset of a string in a Label.
The MacTerminal that is part of the XtermSharp project also uses this feature of Cocoa.
QML also has something for this: HTML and CSS. Yes, you are still on a blog post that describes the UI for a terminal application.
So QML uses its already built in web capabilities to provide rich text formatting.

HTML and CSS

OK, so lets just try that approach, right? I implemented the rendering functionality that translated the terminal content into a string with HTML markups (basically spans with styles).
First test run revealed that the performance of that thing dropped extremely hard. No way that this approach is by any means acceptable even by me and even less by a random user that might be interested in my take of a terminal application.

So I spent a couple of hours (read: evenings) trying to optimize that approach:

  • create a label for each line - this resulted in a very complex logic on QML side (We don’t have that low level access C++ would have) written in Javascript. Performance was a bit better but still nowhere near I wanted it to be
  • separated background color from the foreground options - the rendering logic already tried to get as many characters as possible into one span by comparing the formatting attributes. When one changed a new span got started. The separation of those two groups allowed me to have nested spans. The background span changed way less often as the foreground span. Performance improvement: almost not noticable
  • One Label per cell - the ultimate unnecessary redraw prevention. Performance was not that bad (not good though) but the logic that had to kick in to create all those labels really went crazy when the window was resized.

Result

So the HTML approach was not going to make me happy. I decided to look for something different.
QML has a control called QQuickPaintedItem. This control is meant to be subclassed and to take over the complete drawing (I think most of the ui devkits have something similar).

So you are basically alone with a blank canvas and can draw whatever you need.
Problem: QML.Net does not have support for this QQuickPaintedItem so I decided to jump in and add that feature. More on that topic in the next post.