Universal GUI ~ = end to misery

For me, the ideal GUI is an app that does not require programming, design, maintenance, and is able to work equally with any language and on any platform without any tweaks. Is it possible in our lifetime we will try to figure it out.

It is easy to individually learn something from Vue / React, JavaFX, Python PyQt, ... but getting data and interacting with the software zoo in a simple and elegant way without thinking about user-OS / browsers / platforms is an unresolved task for such tools. I don’t want to get into the new framework (even the old, forgotten), changing the programming language, raking the rake and clogging my head with garbage. I want to program exactly my task, without being distracted by the struggle with all sorts of GUI frameworks. And I found a solution for myself.

As an exchange protocol, we will use Json as the top format in terms of popularity / comprehensibility / readability / support for all programming languages ​​to one degree or another.

The server sends Json data, according to which our app GUI should design a picture that satisfies the specs of a beautiful GUI. Google with its Material Design is today the standard, so take it.

The requirements for a modern GUI include the presence of standard elements, such as buttons, input fields, tables, etc. Let us estimate how to use the minimum set of conventions to tell the GUI that we need certain elements on the screen. Here are the main ones:

  • Stateless button {'name': 'Push me'}. If the element contains only a name, then it is a button.
  • The input field is {'name': 'Edit me', 'value': ''} because the type value is a string.
  • The switcher button {'name': 'My state', 'value': false} because the type false is boolean.
  • Select from the list {'name': 'Switch something', value: 'choice1', options = ['choice1', 'choice2', 'choice3']}
  • {‘name’:’Image, ‘url'’: ’..’, ‘width’: .., ‘height’:… }
  • {‘name’:’My table’, 'headers'=[‘Name’, ‘Synonym’], rows = [
    [‘young’, ‘youthful’],
    [‘small’, ‘ meager’],
    ...]
    }

For customization, you can set the element type to {type: 'ButtonSwitcher'} if the type automatically selected by JSON does not suit you. This is possible when the same JSON can be displayed in more than one way. For example, 'Select from a list' can be represented as an input field with a drop-down list, or it can also be a horizontal set of buttons, one of which is active and corresponds to the current value.

With a small number of options it makes sense to automatically use the button option, with a large number (more than 3) - an input-selection field. Our GUI itself chooses the best way for rendering, but if you really need it - type: ... to help. Normally, the type is not needed and the car designer must cope on his own.

Let's complete the picture in detail:

  • if the name should not be displayed on the screen, it must begin with _;
  • - , ‘icon’: ‘ Material Design ’; push - {‘name’: ‘_Check’, ‘icon’: ‘check’}
  • , Viewers, , ‘colors’, ‘params’,… // . — , .

For the logical grouping of elements, we introduce the concept of a block that groups logically related elements into one visual block.

{'name': 'Block 1', 'elems': [{'name': '_Check', 'icon': 'check'}, ...]}
Within the block, all elements must have unique names, because they are id .

Normally, blocks are built horizontally if they cannot fit everything on the screen (they started the app GUI on a mobile, for example), the auto designer hides them, but adds icons to the toolbar that allow them to be opened with a tap. This gives you the option of working with a complex GUI even on small screens.

The top level of description is Screen. It looks like {'name': 'Screan', blocks: [..], menu: [{'name': 'Screen', 'icon': ..,}, ..], 'toolbar': [JSON set - elements (buttons, fields, whatever)]}

Add implementation details for the conditional uniGUI that supports our JSON protocol. It is a separate process that communicates with the Websocket data server and provides the display of its data with subsequent reporting of all updates of this data that are important for the server.

When connecting to the server, uniGUI expects to receive Screen. Having received it, he designs and draws the resulting info in an optimal way for the current screen for the user, then he waits for a reaction from the user and the server. From the constructed data image, the server receives a stream of JSON messages that fully describe what the user did. They have the form ['Block', 'Elem', 'type of action', 'value'], where 'Block' and 'Elem' are the names of the block and element, value is the value of the event.

The server can either accept the change or roll them back by sending an info window about the discrepancy. It can raise a dialog box, which is described as a block, and has additional. the 'buttons' parameter, which describes the buttons on the dialog. The client instantly displays the current server data and their changes. Only objects changed by the server are sent. To receive events and ensure their processing, we will make a Websocket layer (framework), which will automatically translate messages into calls to handlers that are associated with our data (objects).

All the magic on the server comes down to the fact that our displayed data should be linked to the layer in such a way as to ensure their automatic translation into JSON and calling back notifications from user activity without any coding. Since it depends on the capabilities of a particular language, then for each language the layer can have different options, both architecturally and specifically.

For example, in one case, the layer has a screenshots folder, each of the modules in which has a description of one screen in Python. At startup, the layer reads the screens, gives the user one with global priority = 0. All data is automatically transmitted using jsonpickle. Complex elements have their own “intelligence”, removing the care of details from the programmer. For example, a table receives a set of rows, in which by default id row may be absent when the number of data in row == the number of elements in headers. In this case, when the user selects a row or edits its contents, the server will send the id to the index in row as id ee. If the number of data in row is one more than in headers, the last element in rows is interpreted as id and it is it that is sent to the server. Such automation greatly simplifies life where you don’t need any specifics,but if you suddenly need it, it is available in the least labor-intensive way.

The task of providing automatic translation in JSON, following a format that occupies one or two pages, is completely solvable in any language (I hope so).

In order not to discuss the applicability of this approach for complex applications, below are screenshots such as described by uniGUI written in flutter. The choice fell on him for multi-platform and the lack of additional layers such as JS / chrome. In the flutter minus, you can write down disgusting desktop support and low quality of the upper layer code (GUI elements), an unpleasant architecture for point updates and managing elements as data, which, however, is treated.



The message flow app GUI -> server looks something like this:

flutter: [Glossary, Terms, =, 658]
flutter: [_Details, Links, @, @Folliculitis]
flutter: [_Details, Links, @, @Adolescent]
flutter: [toolbar, _Back, =, _Back]
flutter: [toolbar, _Forward, =, _Forward]
flutter: [toolbar, _Back, =, _Back]
flutter: [_Details, _Status, =, Virtual]
flutter: [_Details, _Status , =, Stable]
flutter: [_Details, Links, @,Inflammation]
flutter: [_Details, _Status, =, Virtual]
flutter: [_Details, _Status, =, Stable]
flutter: [toolbar, _Back, =, _Back]
flutter: [_Details, Links, @, @Folliculitis]

Will there be slow down such a GUI when waiting for events from the server. No, because the GUI works in the server notification mode, reacting to all user actions as a normal local GUI. By default, it considers the server silence on user actions as Ok. When changing screens, it is clear that its description should come. There may be a delay compared to the typical app c embedded GUI.

Total. It is possible today, on current tools, to make a GUI that removes 90% of the standard dreary service code and not bother where and how it will work. At least for business / science applications. This article is a Proof of concept that creating a conditional App Browser is not only possible, but necessary.

All Articles