DEV Community

Cover image for Web Application Programming in PicoLisp: Prefix Classes
Mia
Mia

Posted on • Originally published at picolisp-explored.com

Web Application Programming in PicoLisp: Prefix Classes

In the last post, we have shown how to create an extremely minimalistic HTML form without any styling. This was the code:

(form NIL
   (gui 'a '(+TextField) 30 "First Name")                    
   (<br>)   
   (gui 'b '(+TextField) 30 "Last Name")                         
   (gui '(+Button) "Send" ) ) 
Enter fullscreen mode Exit fullscreen mode

Today we will show how we can add styles and other things to our code using Prefix Classes.

Go here to view the hosted demo page.


What are Prefix Classes?

As explained in the Object-Oriented Programming posts, classes can inherit methods and properties of one or more other classes. This concept is called "multiple inheritance". If the same method or property appears several time within these classes, the first appearance is the valid one.

Technically, there is nothing special about prefix classes. They are just normal classes. They are called "prefix" because they are intended to be written before other classes in a class's or object's list of superclasses.

Prefix Classes can be used to add or modify characteristics that are defined within the GUI class. For example, the the prefix class +Mono displays text in monospace, while +Tinydisplays it in tiny font.


The +Style Prefix Class

By using the Style-prefix class, we can add CSS styles to our GUI classes. Let's modify our example so that it utilizes again the Bootstrap-classes from our previous example.

(action
   (html 0 "Simple Session" *Css NIL
      (<div> "d-flex flex-column"
         (<h1> "d-flex m-5 justify-content-center" "A little POST example with the GUI framework") )
      (<div> "d-flex flex-column bg-light mx-5"
         (<div> "d-flex justify-content-center my-5"

            (form NIL
               (gui 'a '(+Style +TextField) "mx-5" 30 "First Name")
               (<br>)
               (gui 'b '(+Style +TextField) "mx-5 my-1" 30 "Last Name")
               (gui '(+Button) "Send" ) ) ) ) )

Enter fullscreen mode Exit fullscreen mode

Then it looks like this:

stateful_gui.png


Initializing: +Init and +Cue

To initialize a field with values, there are two possibilities:

  • the +Init class populates the field with a value. If the user clicks inside the field, the text will be preserved.

initclass.png

  • the +Cue class populates the field with the specified text inside angled brackets: <my text>. When the user clicks inside the field, it disappears. Note that the text only appears after sending the form, i. e. if a mandatory field has been left blank.

Cueclass.png


Enabling and Disabling: Able, Lock, (disable) and +Rid

Sometimes we need to enable or disable forms or single elements. The easiest way to do that is by using the Prefix Class +Lock, which doesn't take any further arguments:

(gui '(+Lock +Style +TextField) "mx-5 mb-2" 30 "Locked Textfield")                               
(gui '(+Lock +Style +Button) "mb-5" "Locked Button" ) 
Enter fullscreen mode Exit fullscreen mode

+Lock.png

The user can't click on any of the fields, they are disabled.


The +Able class is more flexible, as it takes an executable argument and disables the field if the argument evaluates to NIL.

(gui '(+Able +Style +TextField) '(< 3 5) "mx-5 mb-2" 30 "Enabled Textfield")
(gui '(+Able +Style +Button) '(< 5 3) "mb-5" "Disabled Button" ) 
Enter fullscreen mode Exit fullscreen mode

The text field is enabled because (< 3 5) evalues to T while the button is disabled because (< 5 3) evaluates to NIL.

ABLE.png


It's also possible to disable the form in total using the disable function, which takes an executable argument. If the argument evaluates to non-NIL`, all elements in the form are disabled **except** the ones with a prefix-class+Rid``:

`
(form NIL
(disable (< 3 5))
(gui '(+Init +Style +TextField) "Disabled textfield" "mx-5 mb-2" 30 "Enter your text: ")
(gui '(+Rid +Init +Style +TextField) "Enabled by +Rid" "mx-5 mb-2" 30 "Enter your text: ") )
`

ridclass.png


The +JSclass

Let's take another look at last post's example, our button that prints a text field's content to standard error.

`
(form NIL
(gui '(+Style +TextField) "mb-2" 30 "Enter your text: ")
(gui '(+Button) "Print" '(msg (val> (field -1))) )
`

When we press the button, the whole page is reloading. Now let's add another button with the same functionality, but prefix class +JS:

`

(gui '(+JS +Button) "Print" '(msg (val> (field -1))) )`

![jsprint.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1633188321665/w0v1Cr5x7.png)

Now let's try both. When we press the button "Print", our page is **reloaded** and our text input is displayed on standard error. If the "+JS Print" button is pressed, our text input is also displayed on standard error, but **without reloading**! *(The only exception is if there is no session running yet. In this case, the page will reload once to establish a session.)*

------------------------

How does it work? Comparing the HTML source code of both buttons, we can see that the ``+JS`` has an additional ``onclick="return doBtn(this)"`` tag and there is a  ``form.js`` script sheet included, which causes the browser to only re-evaluate the GUI elements without reloading the full page. 

-------------------------

### Defining variables with ``+Var``

Usually if we have a form sheet, we want to do something with the data. Say we want to write this data to a global variable called ``*TextVariable``. When the button ``Print`` is pressed, this data should be written to standard output. Also, we want to print the content of the variable as normal text block.

In order to do all this, we will use the prefix class ``+Var``, which takes a variable name as argument:

Enter fullscreen mode Exit fullscreen mode

(setq *TextVariable "Initial Value")
(gui '(+Style +Var +TextField) "mb-2" '*TextVariable 30 "Enter your text: ")
(gui '(+Style +JS +Button) "mb-5" "+JS Print" '(msg (val> (field -1)))))
(

(prinl "*TextVariable: " *TextVariable)))))


The page is initialized with a text field and text block content "Initial Value". 

![textvar1.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1633190010307/qzf7JJmXw.png)

Now let's modify the value and press ``+JS Print``. Immediately we see our new value in the standard error of the server process. However, the ``<p>``-block remains unchanged, because the page has not been reloaded. 

![textavr1.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1633190176031/XXobuVtMq.png)


--------------------

### Modifying values with ``+Val`` and ``+Set``

We already heard that each gui object has a method ``val>`` to return the value of a property, and ``set>`` to set its value. These methods are inherited from the abstract top class ``+gui``.

However, there might be situations where we want to customize these methods to our own needs. This can be done using the prefix classes ``+Val`` and ``+Set`` respectively. Both take a function as argument that overwrites the methods ``val>`` and ``set>`` respectively. Let's look at the following example:

Enter fullscreen mode Exit fullscreen mode

(gui '(+Val +NumField) '((N) (* N N)) 10 "Enter a number: ")
(gui '(+Style +Button) "mb-3" "get square value" )

We have a number input field. However, the **value** of the field is not the content, but its square, because the value is multiplied with itself each time it is retrieved:

![getsquare.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1633190892914/DWHHCfFB4.png)

If we type ``10`` and press the button, the field content becomes ``100``, if we press again, ``10000``.

-------------------

The complement to ``+Val`` is ``+Set``. It is called everytime a value is set to another value. 

Enter fullscreen mode Exit fullscreen mode

(gui '(+Set +NumField) '((N) (* N N)) 10 "Enter a number: ")
(gui '(+Style +Button) "mb-3" "get square value" )


Look and feel of that function are exactly identical to the ``

+Val`` version, so what's the difference?

The difference is how the data is stored internally. Say we type ``10`` and press the button. In the ``+Val`` case, the actually stored value is ``10``, although the displayed value is ``100``. In the ``+Set`` case, the actually stored value is ``100``.

--------------------

The source code of the examples can be found [here](https://gitlab.com/picolisp-blog/web-applications/-/blob/main/gui-elements/prefix-classes.l).

--------------------

These were some of the most important prefix classes. In the next post, we will take a look at some further GUI elements.

--------------------

### Sources:

- https://software-lab.de/doc/form/form.html   
- https://software-lab.de/doc/app.html   
Enter fullscreen mode Exit fullscreen mode

Top comments (0)