Web Apps: GUI Component Interaction
Published: 2022-02-19 10:20:47

### [Task](http://rosettacode.org/wiki/GUI_component_interaction)

> For a minimal "application", write a program that presents a form with three components to the user:
   - a numeric input field ("Value")
   - a button ("increment"
   - a button ("random")

> The field is initialized to zero. The user may manually enter a new value into the field, or increment its value with the "increment" button. Entering a non-numeric value should be either impossible, or issue an error message.

> Pressing the "random" button presents a confirmation dialog, and resets the field's value to a random value if the answer is "Yes". 

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

This task is very similar to the previously discussed task ["Simple Windowed Application"](https://picolisp-blog.hashnode.dev/webapps-a-simple-windowed-application), so we will use the script and modify it. This is how it will look like in the end:


![guicomponent.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1634283230053/F4fxoqF6Q.gif)

A hosted version can be found [here](http://picolisp.com/blog/src/GUI-Component-Interaction.l).
 
--------------------------------

### Defining the GUI elements

In this task, we need a numeric input field that can be modfied by the user, a button called "increment" and another button called "random". Let's define them without putting any logic inside:

```
(gui '(+NumField) 20 "Value: ")
(gui '(+Button) "increment")
(gui '(+Button) "random")
```

![gui-compoennts.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1633259931005/_E1qGQoug.png)

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

### Define the logic

We want the ``+NumField`` to show us the value of the ``*Count`` variable, and also be able to modify it. We can do this by setting the prefix class ``+Var`` on the ``*Count`` variable:

```
(gui '(+Var +NumField) '*Count 20 "Value: ")
```
Secondly, we want the button to increase the ``'*Count`` value. So lets add a function to the button definition:

```
(gui '(+Button) "increment" '(inc '*Count))
```

And the prefix class ``+JS`` to avoid the reload of the complete page.

```
(gui '(+JS +Button) "increment" '(inc '*Count))
```

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

As last step, we need to define the random function. PicoLisp has a built in function called ``rand`` which can be used for that purpose: 

> ``(rand ['cnt1 'cnt2] | ['T]) -> cnt | flg``

> Returns a pseudo random number in the range of the positive short numbers ``cnt1`` and ``cnt2`` (or -2147483648 .. +2147483647 if no arguments are given). If the argument is ``T``, a boolean value ``flg`` is returned.

The task description has no specification about the range, so let's use the ``rand`` function without any arguments. When the button is pressed, we set ``*Count`` to the random value.

```
(gui '(+Button) "random" '(setq *Count (rand)))
```

![random.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1633265885120/AQOfoctyF.png)

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

There is only one last specification to fulfill: The task description tells us that we need to open a **dialog** which needs to be confirmed by the user first. ``form.l`` provides a function ``ask`` for this purpose:

> ``(ask Str . Prg)``

> Creates an alert dialog with a string, a 'Yes'- and a 'No'-button. ``Str`` is the text that will populate the alert, ``Prg`` is the action triggered by the 'Yes'- button.


![dialog.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1633266174491/3XbdO5oHv.png)

As you can see, the pop-up moves the position of all the other components, because it's not an overlay dialog box but a normal ``<form>`` element that is inserted just above the form which created them.

```
<form enctype="multipart/form-data" ...> ...
   <fieldset class="alert"> ...
   <span class="ask">Reset to a random value?</span><br/>
   <input type="submit" name="*Gui:-1" value="Yes" onmousedown="inBtn(this,1)" onblur="inBtn(this,0)" class="submit" id="i0--1"/>
   <input type="submit" name="*Gui:-2" value="No" onmousedown="inBtn(this,1)" onblur="inBtn(this,0)" class="submit" id="i0--2"/>
   </fieldset>
</form>
```

There is not so much we can do about the shifting, but at least we can make sure that it is inserted **above instead of next to our form GUI elements** by wrapping these into their own ``<div>`` within the ``form`` function:

```
(<div> "d-flex flex-column bg-light text-center mx-5"

    <-- Dialog comes here! -->

   (form NIL
      (<div> "d-flex justify-content-center text-center my-5"
         (gui '...)   
         (gui '...)   
```
Due to the ``text-center`` class in the ``<div>`` above the dialog it gets centered. Then it looks like this:

![resetdialog.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1633268328580/DXHXhB3HW.png)

Now our form elements get pushed down when the dialog box appears, but not to the side. Finished!

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

The final source code can be downloaded [here](https://gitlab.com/picolisp-blog/web-applications/-/blob/master/rosetta-code/GUI-Component-Interaction.l), css [here](https://gitlab.com/picolisp-blog/web-applications/-/blob/master/rosetta-code/bootstrap.css).


---------------------------
### Sources
- https://rosettacode.org/wiki/GUI_component_interaction#PicoLisp  
- https://software-lab.de/doc/app.html#dialogs