Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 22:42 25 May 2026 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : MMBasic V6.03.00 release candidates

     Page 11 of 12    
Author Message
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 11367
Posted: 11:00am 23 May 2026
Copy link to clipboard 
Print this post

  Quote  I was thinking function CWD$ is a likely candidate for an overlaid function, it should not be in use where performance is an issue.

I tried it as well as POS and I've had to back them both out as there were too many side effects.

This should give me a bit of headroom
      STR_REPLACE((char *)inpbuf, "BIN$(", "BASE$(2,", 3);
       STR_REPLACE((char *)inpbuf, "OCT$(", "BASE$(8,", 3);
       STR_REPLACE((char *)inpbuf, "HEX$(", "BASE$(16,", 3);
       STR_REPLACE((char *)inpbuf, "LCASE$(", "SCHANGE$(L,", 3);
       STR_REPLACE((char *)inpbuf, "UCASE$(", "SCHANGE$(U,", 3);
       STR_REPLACE((char *)inpbuf, "MIN(", "TOPBOTTOM(I,", 3);
       STR_REPLACE((char *)inpbuf, "MAX(", "TOPBOTTOM(A,", 3);
       STR_REPLACE((char *)inpbuf, "LEFT$(", "SCHANGE$(E,", 3);
       STR_REPLACE((char *)inpbuf, "RIGHT$(", "SCHANGE$(R,", 3);
 
toml_12953
Guru

Joined: 13/02/2015
Location: United States
Posts: 644
Posted: 11:42am 23 May 2026
Copy link to clipboard 
Print this post

  mozzie said  
Couple of minor bugs plus the previous comment above regarding CLICK:

BIT command is replaced with : in programs.
pos becomes POS in command and variable names.

Regards, Lyle.


I was wondering why MATH m_transpose a(),b()

came back with an error

MATH m_transPOSe a(),b()
 
toml_12953
Guru

Joined: 13/02/2015
Location: United States
Posts: 644
Posted: 12:02pm 23 May 2026
Copy link to clipboard 
Print this post

I'm trying to write a SUB that takes a variable number of arguments. The manual seems to say it's possible but the following doesn't work. Why?

DIM a(2,2)=(1,2,3,4,5,6,7,8,9)
MAT "PRINT",a()

SUB MAT(funct$,a(),b())
 SELECT CASE UCASE$(funct$)
   CASE "PRINT"
     MATH m_print a()
 END SELECT
END SUB


[2] mat "print",a()
Error : Expected an array
Edited 2026-05-23 22:03 by toml_12953
 
toml_12953
Guru

Joined: 13/02/2015
Location: United States
Posts: 644
Posted: 12:15pm 23 May 2026
Copy link to clipboard 
Print this post

Is there a way for a function to return an array? I don't mean change one of its parameters which are passed by reference but set the function name to an array before exiting the function:

b() = INV(a())

function INV(n())
 local z(bound(n()),bound(n(),2))
 math m_inverse n(),z()
 INV = z()
end function

Edited 2026-05-23 22:16 by toml_12953
 
disco4now

Guru

Joined: 18/12/2014
Location: Australia
Posts: 1124
Posted: 12:19pm 23 May 2026
Copy link to clipboard 
Print this post

  matherp said  

This should give me a bit of headroom
      STR_REPLACE((char *)inpbuf, "BIN$(", "BASE$(2,", 3);
       STR_REPLACE((char *)inpbuf, "OCT$(", "BASE$(8,", 3);
       STR_REPLACE((char *)inpbuf, "HEX$(", "BASE$(16,", 3);
       STR_REPLACE((char *)inpbuf, "LCASE$(", "SCHANGE$(L,", 3);
       STR_REPLACE((char *)inpbuf, "UCASE$(", "SCHANGE$(U,", 3);
       STR_REPLACE((char *)inpbuf, "MIN(", "TOPBOTTOM(I,", 3);
       STR_REPLACE((char *)inpbuf, "MAX(", "TOPBOTTOM(A,", 3);
       STR_REPLACE((char *)inpbuf, "LEFT$(", "SCHANGE$(E,", 3);
       STR_REPLACE((char *)inpbuf, "RIGHT$(", "SCHANGE$(R,", 3);


Hi Peter,
See these from CMM2.There was an issue with these if used as the ending of a function e.g. a function called converttoHEX$(123)
//fix for HEX$ replaced in  converttoHEX$(123) function
I used 2 in lieu of 3 for the ignoresurround parameter to prevent it.
It seems to fix that issue and still work.


   STR_REPLACE(inpbuf,"BIN$(","BASE$(2,",2);   //fix for HEX$ replaced in converttoHEX$(123) function
   STR_REPLACE(inpbuf,"OCT$(","BASE$(8,",2);
   STR_REPLACE(inpbuf,"HEX$(","BASE$(16,",2);


F4 H7FotSF4xGT
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 11367
Posted: 12:34pm 23 May 2026
Copy link to clipboard 
Print this post

  Quote  It seems to fix that issue and still work.

 
phil99

Guru

Joined: 11/02/2018
Location: Australia
Posts: 3229
Posted: 12:36pm 23 May 2026
Copy link to clipboard 
Print this post

@toml_12953 it only appears to be a problem with arrays
Dim a(2,2)=(1,2,3,4,5,6,7,8,9)

Sub MAT funct$, a(), b
 Select Case UCase$(funct$)
 Case "PRINT"
 Math m_print a()
 End Select
End Sub

MAT "PRINT", a()
End

> RUN
  1.0000,    2.0000,    3.0000
  4.0000,    5.0000,    6.0000
  7.0000,    8.0000,    9.0000
>
 
disco4now

Guru

Joined: 18/12/2014
Location: Australia
Posts: 1124
Posted: 12:41pm 23 May 2026
Copy link to clipboard 
Print this post

  toml_12953 said  I'm trying to write a SUB that takes a variable number of arguments. The manual seems to say it's possible but the following doesn't work. Why?

I am not sure exactly why but when I wrote some unit tests when the BYVAL, BYREF parameters where added these two restrictions are there and were always there when passing parameters to a SUB.

' The first parameter cannot be empty- always been that way
' An array must always be provided if defined - always been that way
F4 H7FotSF4xGT
 
terekgabor
Regular Member

Joined: 02/01/2026
Location: Hungary
Posts: 81
Posted: 04:00pm 23 May 2026
Copy link to clipboard 
Print this post

Peter!

I just thinked about can be good some instruction to manipulate fonts.
Change characters in a font set, make custom characters from program.
Now we can only put definefont in the program. And I can read font information with Peek.

G@bor
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 11367
Posted: 04:57pm 23 May 2026
Copy link to clipboard 
Print this post

Have you looked at the GUI BITMAP command - should do exactly what you want. It uses exactly the same data format as a single character in a font
 
okwatts
Regular Member

Joined: 27/09/2022
Location: Canada
Posts: 67
Posted: 05:26pm 23 May 2026
Copy link to clipboard 
Print this post

I note a problem with program 2048.bas under 6.03RC11 (apart from having to edit the MAP variable to MMAP). When run it starts but trying to move using the arrow keys it complains that for either row or col there is a next without a for. Works fine on 6.02.01, this is on the HDMIUSBI2S board with the standard platform options and the PSRAM enabled. I hadn't tried this on earlier 6.03 releases so not sure when this crept in.
2048_v6.zip
 
terekgabor
Regular Member

Joined: 02/01/2026
Location: Hungary
Posts: 81
Posted: 05:29pm 23 May 2026
Copy link to clipboard 
Print this post

  matherp said  Have you looked at the GUI BITMAP command - should do exactly what you want. It uses exactly the same data format as a single character in a font


Yes I have checked. You are right, I will try this.

Thanks!
 
flip
Senior Member

Joined: 18/07/2016
Location: Australia
Posts: 124
Posted: 02:33am 24 May 2026
Copy link to clipboard 
Print this post

Hi all,
I can't seem to run structures any more in RC11 after successfully running the Screens demo above.
I did a OPTION GUI CONTROLS 0 just in case there was some PSRAM allocation error, but no difference
I obscured names of variables but it doesn't look like any new keywords are impacting.
Looking at 2026-01-10_040853_MMBasic_Structures_Manual.pdf, I don't think any options are required for PSRAM assignment required...but as before I could be overthinking while paddling up the wrong stream.
 ...
 ...
 Option EXPLICIT
 Option DEFAULT NONE

Type tBox
 bLeft As integer
 bTop As Integer
 bWidth As Integer
 bHeight As Integer
 bFore As Integer
 bBack As Integer
 bHiFore As Integer
 bHiBack As Integer
 bHeading As String
 bFont As integer
End Type
 Dim Boxes(255) As tBox
...
...
> ram run 2
[46] Dim Boxes(255) As tBox
Error : Not enough PSRAM memory
>

(I also RAM LOAD 2 into main memory but still same problem running from there)
Again using the HDMI 4xUSB I2S Silicon Chip build.
Can someone confirm or point me to my problem?
PS. loving all the developments - thanks Peter and Geoff!
Regards Phil
 
flip
Senior Member

Joined: 18/07/2016
Location: Australia
Posts: 124
Posted: 05:23am 24 May 2026
Copy link to clipboard 
Print this post

My problem with PSRAM was resolved by resetting PSRAM:
OPTION PSRAM PIN DISABLE
OPTION PSRAM PIN {pinno}

Note the 5 x RAM Code sections of PSRAM worked fine throughout(i think they're at fixed addresses) which is a good thing
Maybe some edge-cases might cause PSRAM allocation/pointer issue, and seemed to only affect when Dim of a Structure used ( Dim Boxes(23) As Integer was accepted fine under the fault condition )
Basically the steps I indicated in my previous post must have done it somehow.
If any more info/tests required happy to help.

Thanks again & Regards Phil
Edited 2026-05-24 15:50 by flip
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 11367
Posted: 06:51am 24 May 2026
Copy link to clipboard 
Print this post

okwatts. thanks for the report. found and fixed
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 11367
Posted: 09:48am 24 May 2026
Copy link to clipboard 
Print this post

V6.03.00RC12
PicoMiteRP2040V6.03.00RC12.zip
PicoMiteRP2350V6.03.00RC12.zip
Fixes bug in For loops introduced as part of optimisations
Finalises GUI controls to be completely flexible touch/no-touch, mouse/no-mouse, external contol keyboard/joystick etc.
Note: Geoff authored the gui controls and they now work in almost every MMbasic environment. All I have done is integrated them into the PicoMite codeset in a way that hopefully makes them more useful in many different scenarios.

  Quote  # `gui-demo-320x240.bas` — Multi-firmware GUI demonstration

## Overview

`gui-demo-320x240.bas` is a single MMBasic program that builds a fake
"Pump Control" panel using every standard GUI widget and then accepts
operator input from whichever device the running firmware happens to
expose:

| Input device           | Mechanism                                                |
| ---------------------- | -------------------------------------------------------- |
| Touch screen           | `GUI INTERRUPT TouchDown, TouchUp`                       |
| Mouse (USB HID or PS/2)| `GUI CURSOR LINK MOUSE`                                  |
| Keyboard               | `INKEY$` loop driving `GUI CURSOR` and `GUI CLICK`       |

The same `TouchDown` / `TouchUp` subs handle every source, so the
application logic is written only once.

The program is laid out for a 320×240 canvas — small enough to run on
the cheapest ILI9341/ILI9488 LCDs and on `MODE 2` of the VGA and HDMI
builds.

## Prerequisite

`GUI` controls are an opt-in feature of MMBasic. Before running the
demo (and only once, from the command prompt — not inside the
program) issue:

```
OPTION GUI CONTROLS 50
```

The number is the upper bound on simultaneous controls. The demo
uses about 25 control reference numbers, so anything ≥ 25 is fine;
fifty was chosen as a safe default for the underlying widget tables.

## Supported firmware

The demo runs unmodified on every build that defines `GUICONTROLS`.
On builds that don't, `GUI` commands raise a syntax error and the
program will not start — they are listed for completeness.

| Build                                | GUI controls | Touch | Mouse                       | Keyboard      |
| ------------------------------------ | :----------: | :---: | --------------------------- | ------------- |
| PicoMite **PICO** (RP2040 LCD)       |     yes      |  yes  | PS/2                        | PS/2          |
| PicoMite **PICOUSB** (RP2040 LCD)    |     yes      |  yes  | USB HID                     | USB HID       |
| PicoMite **PICORP2350**              |     yes      |  yes  | PS/2                        | PS/2          |
| PicoMite **PICOUSBRP2350**           |     yes      |  yes  | USB HID                     | USB HID       |
| PicoMiteVGA **VGARP2350**            |     yes      |   —   | PS/2                        | PS/2          |
| PicoMiteVGA **VGAUSBRP2350**         |     yes      |   —   | USB HID                     | USB HID       |
| PicoMiteHDMI **HDMI**                |     yes      |   —   | PS/2                        | PS/2          |
| PicoMiteHDMI **HDMIUSB**             |     yes      |   —   | USB HID                     | USB HID       |
| WebMite **WEBRP2350** (with LCD)     |     yes      |  yes  | PS/2                        | PS/2          |
| PicoMiteBT **PICOBTRP2350**          |     yes      |  yes  | PS/2                        | PS/2 + BT HID |
| PicoMiteBT **PICOBTHRP2350**         |     yes      |  yes  | USB HID                     | USB HID + BT  |
| WebMite **WEB** (RP2040)             |    **no**    |   —   | —                           | —             |
| PicoMiteVGA **VGA** / **VGAUSB** (RP2040) | **no**  |   —   | —                           | —             |
| PicoMite **PICOMIN**                 |    **no**    |   —   | —                           | —             |

A few notes that aren't obvious from the table:

* "PS/2" rows are non-USB-host builds and pick up a mouse via
 [mouse.c](../mouse.c) on the configured `MOUSE_CLOCK` /
 `MOUSE_DATA` pins. "USB HID" rows are USB-host builds and pick up a
 mouse through [USBKeyboard.c](../USBKeyboard.c) (`HID[1].Device_type == 2`).
* RP2040 VGA / WebMite firmware compiles the mouse driver but does
 **not** define `GUICONTROLS` — the `Ctrl[]` heap reservation is too
 expensive for the available RAM. See [CMakeLists.txt:534-538](../CMakeLists.txt#L534-L538).
* The WEBRP2350 build *does* enable `GUICONTROLS` and *does* drive an
 attached LCD ([CMakeLists.txt:577](../CMakeLists.txt#L577)); the
 plain RP2040 WEB build does not.

## How "one program runs everywhere" actually works

The program uses four small techniques to absorb firmware
differences. Each is explained below.

### 1. Force a known display mode on VGA / HDMI

LCD builds boot with `MM.HRES = 320`, `MM.VRES = 240` already, so all
the hard-coded pixel coordinates land in the right place. VGA and
HDMI builds boot at a higher resolution, which would push the layout
off the visible area.

```basic
If InStr(MM.DEVICE$, "VGA") Or InStr(MM.DEVICE$, "HDMI") Then
 MODE 2          ' selects 320x240 on both VGA and HDMI builds
EndIf
```

`MM.DEVICE$` is the only reliable cross-firmware identifier; the
demo uses it as the single source of truth for "do I need to switch
resolution?".

### 2. Turn the soft cursor on, then sync it to whatever the user is using

`GUI CURSOR ON` enables a *soft* cursor — a sprite that the firmware
overlays on the screen by saving and restoring the pixels beneath it.
Mouse and keyboard input naturally move that cursor; the touch path
does not, so the demo updates it explicitly inside `TouchDown`:

```basic
Sub TouchDown
 Local Integer tx, ty
 tx = Touch(x) : ty = Touch(y)
 If Not (tx = -1 Or ty = -1) Then
   GUI Cursor tx, ty        ' make the cursor follow the finger
   mx = tx : my = ty        ' keep the keyboard's idea in step
 EndIf
 ...
```

The result is that, no matter which input device the user picks up
next — finger, mouse, or arrow keys — the cursor is already at the
last interaction point.

### 3. Try to link the cursor to a real mouse

```basic
On Error Skip
GUI Cursor Link Mouse
```

`GUI CURSOR LINK MOUSE` exists on every build that defines
`GUICONTROLS`, regardless of mouse type — it is the same command for
USB HID and PS/2. What it raises at run time is **"No mouse
connected"** if `cursor_have_mouse()` cannot find a live mouse
([Draw.c:1046-1059](../Draw.c#L1046-L1059)). That is the case the
`On Error Skip` is there for: the demo wants to keep running and use
touch / keyboard, not abort because the user didn't plug in a mouse.

The probe also gracefully handles any historical firmware that
predates the `LINK MOUSE` subcommand and reports it as a syntax
error.

Once linked, the soft cursor follows the physical mouse and the
mouse's left button is dispatched through the same touch machinery
described next.

### 4. Unify all three input paths through the touch interrupt

```basic
GUI Interrupt TouchDown, TouchUp
```

`TouchDown` and `TouchUp` are fired for:

* A real touch from the LCD panel.
* A real click from a linked mouse (USB HID or PS/2 — `GUI CURSOR
 LINK MOUSE` re-routes mouse-button events into the touch
 dispatcher).
* A synthetic `GUI CLICK` issued from the keyboard fallback loop —
 the engine dispatches `GUI CLICK` through the *same* code path as a
 touch, so the interrupts fire there too.

That last point is what removes all per-input-source branching from
the program. There is no "if touch then... else if mouse then..." —
every input shows up at `Touch(REF)` in `TouchDown` as the control
the cursor was over when the click happened.

### 5. Keyboard fallback loop

For builds where neither touch nor mouse is available at the moment
(a bare HDMI build with no mouse plugged in, for example), the main
`Do … Loop` provides a pointer the user can drive from any PS/2 or
USB keyboard:

| Key          | Action                                                   |
| ------------ | -------------------------------------------------------- |
| ← → ↑ ↓      | Move the soft cursor by `stepx` pixels (4 px)            |
| Space        | `GUI Click mx, my` — momentary press-release             |
| `D` / `d`    | `GUI Click Down` — start a held press                    |
| `U` / `u`    | `GUI Click Up` — release the held press                  |
| `Esc`/`Q`/`q`| Exit the program cleanly                                 |

After each move the cursor coordinates are clamped to the visible
canvas so the cursor cannot run off-screen and lose its background.

The held-press support exists so this same demo can be reused as a
drag-test harness: press `D`, walk the cursor across the screen with
the arrow keys, then `U`. MMBasic binds the click to whichever
control was hit on `Down`, so dragging across other controls does
not retrigger them — matching real touch and real mouse behaviour.

On the way out, the loop calls `GUI Click Up` if a key chord was
left half-finished, then `GUI Cursor Off`, so the system is left in
a clean state for the next program.

## The control set

The "Pump Control" panel uses one of every widget supported by GUI
CONTROLS:

| Widget       | Purpose in this demo                                  |
| ------------ | ----------------------------------------------------- |
| `Caption`    | Static labels (heading, "Pump", "Flow Rate", "Hi:" …) |
| `Switch`     | Pump ON / OFF                                         |
| `Displaybox` | Read-only flow-rate value                             |
| `Frame`      | Visual grouping (Power, Alarm, Log File)              |
| `Radio`      | Power mode: Economy / Normal / High                   |
| `Numberbox`  | Editable Hi and Lo alarm thresholds                   |
| `Button`     | Momentary "TEST" alarm                                |
| `LED`        | Status indicators ("Running", "Alarm")                |
| `Checkbox`   | Logging enable + per-event filters                    |
| `Textbox`    | Log file name                                         |
| `Spinbox`    | Back-light percentage                                 |

Every control declares a reference number (a small integer) via
`Const`. Those constants are passed to `GUI` commands when the
control is built, and matched against `Touch(REF)` in the interrupt
handler.

## What each control actually does

The application logic lives entirely inside `TouchDown` / `TouchUp`:

* `sw_pmp` (the pump switch) — copies its state to the green
 "Running" LED, recomputes the flow-rate display, and forces the
 power-mode radio group back to Normal.
* `r_econ` / `r_norm` / `r_hi` — recompute the displayed flow rate
 using a different multiplier (18.3, 20.1, 23.7). When the pump is
 off, multiplying by `CtrlVal(sw_pmp) = 0` yields zero.
* `pb_test` (the "TEST" button) — lights the red "Alarm" LED on
 `TouchDown`, extinguishes it on `TouchUp`. This is the only control
 that uses both interrupts; everything else is a momentary action.
* `cb_enabled` — enables or disables the four logging-related widgets
 with `GUI Restore` / `GUI Disable`. Disabled widgets are drawn dim
 and ignore further input.
* `sb_bright` — feeds its value (10–100 in steps of 10) straight to
 the firmware `Backlight` command. On firmware without a controllable
 backlight, `Backlight` is a no-op.

Numberboxes (`nbr_hi`, `nbr_lo`) and the file-name textbox
(`tb_fname`) do not appear in the `Select Case` at all — they are
edited in place by the firmware's built-in input handler, and the
program would simply read their current `CtrlVal(...)` if it were
doing real work.

## Layout

The screen is divided into three vertical columns:

```
+-----------+--------+--------------+
| Pump      | LEDs   | Log File     |
| Switch    | Run    | [x] Log On   |
|           | Alarm  | File Name    |
| Flow Rate |        | LOGFILE.TXT  |
|  20.1     | Alarm  |              |
|           | Hi: 35 | Record:      |
| Power     | Lo: 16 | [x] Flow     |
|  o Econ   | [TEST] | [x] Alarms   |
|  * Normal |        | [x] Warnings |
|  o High   |        |              |
|           |        | Back Light   |
|           |        | [- 100  +]   |
+-----------+--------+--------------+
```

All x/y coordinates are absolute pixel positions inside the 320×240
canvas. The numbers chosen by the original author have been preserved
unchanged so the demo continues to render identically on every
firmware build it has historically been tested on.

## Extending the demo

* **Add a new control**: pick an unused reference-number constant,
 declare it at the top of the file, create the widget in the build
 section, and add a `Case` in `TouchDown` (and optionally
 `TouchUp`).
* **Add a new input source**: do nothing. As long as the new device
 ultimately drives `GUI CURSOR` + `GUI CLICK` or fires the touch
 interrupt, the existing handlers will pick it up.
* **Run on a different resolution**: change the four section anchors
 (the column-x positions 5, 115, 210 and the LED column at 125), or
 move the `MODE 2` guard to select a larger mode and re-flow the
 layout. The compatibility scaffolding is independent of the
 layout numbers.



'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Pump-control GUI demo for MMBasic builds with GUI CONTROLS
' -----------------------------------------------------------------
' Demonstrates the standard GUI widgets (caption, switch, displaybox,
' frame, radio, numberbox, button, LED, checkbox, textbox, spinbox)
' driven by whichever input methods the firmware happens to expose:
'
'   Touch screen .... via GUI INTERRUPT TouchDown, TouchUp
'   USB mouse ....... via GUI CURSOR LINK MOUSE
'   Keyboard ........ via INKEY$ + GUI CURSOR / GUI CLICK
'
' All three routes end up in the same TouchDown / TouchUp subs, so the
' program contains no per-input-source branching: each control is
' handled once, regardless of where the click came from.
'
' Layout is hand-placed for a 320x240 canvas so the program runs on
' the smallest LCD panels; on VGA/HDMI builds the program switches to
' MODE 2 (320x240) to keep the layout intact.
'
' Geoff Graham, October 2015 (original)
' Modified for ILI9341 by Phil23
' Refactored for multi-firmware input by Peter Mather, 2026
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Option Explicit

' ----- control reference numbers ---------------------------------
Const c_head     = 1,  c_pmp     = 2,  sw_pmp    = 3
Const c_flow     = 4,  tb_flow   = 5
Const led_run    = 6,  led_alarm = 7
Const frm_alarm  = 20, nbr_hi    = 21, nbr_lo    = 22, pb_test = 23
Const c_hi       = 24, c_lo      = 25
Const frm_pump   = 30, r_econ    = 31, r_norm    = 32, r_hi    = 33
Const frm_log    = 40, cb_enabled= 41, c_fname   = 42, tb_fname= 43
Const c_log      = 44, cb_flow   = 45, cb_pwr    = 46, cb_warn = 47
Const cb_alarm   = 48, c_bright  = 49, sb_bright = 50

' ----- layout constants ------------------------------------------
Const ledsX = 125              ' x column shared by both LEDs
Const stepx = 4                ' keyboard cursor step in pixels

' ----- runtime state ---------------------------------------------
Dim Integer cw, ch             ' canvas width / height
Dim Integer mx, my             ' soft-cursor position
Dim Integer ledsY              ' running y while stacking the LEDs
Dim Integer held               ' 1 while GUI CLICK DOWN is in effect
Dim String  k$

' =================================================================
' Display + input device setup
' =================================================================
Colour RGB(white), RGB(black)
CLS

' VGA/HDMI firmware boots in a larger mode; force 320x240 so the
' hard-coded coordinates below land in the right place.
If InStr(MM.DEVICE$, "VGA") Or InStr(MM.DEVICE$, "HDMI") Then
 MODE 2
EndIf

cw = MM.HRES : ch = MM.VRES
mx = cw \ 2  : my = ch \ 2

' The soft cursor is required for mouse and keyboard input. Touch-only
' firmware accepts the command and simply never moves the cursor.
GUI Cursor On

' GUI CURSOR LINK MOUSE only exists on builds with USB host support.
' "On Error Skip" lets older firmware silently continue.
On Error Skip
GUI Cursor Link Mouse

' Both real touches and GUI CLICK (used by the keyboard fallback)
' dispatch through this interrupt pair.
GUI Interrupt TouchDown, TouchUp

' =================================================================
' Build the pump-control display
' =================================================================

' --- heading and pump label --------------------------------------
Font 2
GUI Caption c_head, "Pump Control", 10, 0
GUI Caption c_pmp,  "Pump",         10, 25, , RGB(brown)

' --- pump ON/OFF switch ------------------------------------------
GUI Switch sw_pmp, "ON|OFF", 10, 45, 70, 30, RGB(white), RGB(brown)
CtrlVal(sw_pmp) = 1                                  ' starts ON

' --- flow-rate read-out ------------------------------------------
GUI Caption    c_flow,  "Flow Rate", 5, 75,  , RGB(brown), 0
GUI Displaybox tb_flow,              5, 100, 105, 25
CtrlVal(tb_flow) = "20.1"

' --- power-mode radio group --------------------------------------
GUI Frame frm_pump, "Power", 5, 140, 105, 90, RGB(200,20,255)
Font 1
GUI Radio r_econ, "Economy", 20, 160, 10, RGB(230,230,255)
GUI Radio r_norm, "Normal",  20, 185
GUI Radio r_hi,   "High",    20, 210
CtrlVal(r_norm) = 1                                  ' default mode

' --- alarm frame: Hi/Lo number boxes + TEST button ---------------
Font 2 : GUI Frame frm_alarm, "Alarm", 115, 115, 90, 115, RGB(green)
Font 1
GUI Caption   c_hi,    "Hi:", 120, 150, LT, RGB(yellow)
GUI Numberbox nbr_hi,         150, MM.VPOS-6, 40, MM.FONTHEIGHT+6, RGB(yellow), RGB(64,64,64)
GUI Caption   c_lo,    "Lo:", 120, 175, LT, RGB(yellow), 0
GUI Numberbox nbr_lo,         150, MM.VPOS-6, 40, MM.FONTHEIGHT+6, RGB(yellow), RGB(64,64,64)
GUI Button    pb_test, "TEST", 125, 200, 70, 25, RGB(yellow), RGB(red)
CtrlVal(nbr_hi) = 35.5
CtrlVal(nbr_lo) = 15.7

' --- two status LEDs, stacked vertically -------------------------
ledsY = 50         : GUI LED led_run,   "Running", ledsX, ledsY, 8, RGB(green)
ledsY = ledsY + 25 : GUI LED led_alarm, "Alarm",   ledsX, ledsY, 8, RGB(red)
CtrlVal(led_run) = 1                                 ' tracks the switch

' --- logging frame: enable, file name, per-event check boxes -----
Colour RGB(cyan), 0
GUI Frame    frm_log,    "Log File",  210, 10,  110, 160, RGB(green)
GUI Checkbox cb_enabled, "Log On",    215, 20,  20, RGB(cyan)
GUI Caption  c_fname,    "File Name", 215, 45
GUI Textbox  tb_fname,                215, 60,  100, 20, RGB(cyan), RGB(64,64,64)
GUI Caption  c_log,      "Record:",   215, 85,  , RGB(cyan), 0
GUI Checkbox cb_flow,    "Flow",      220, 100, 20
GUI Checkbox cb_alarm,   "Alarms",    220, 120, 20
GUI Checkbox cb_warn,    "Warnings",  220, 140, 20
CtrlVal(cb_enabled) = 1
CtrlVal(tb_fname)   = "LOGFILE.TXT"

' --- backlight spinbox -------------------------------------------
GUI Caption c_bright, "Back Light", 230, 190, , RGB(200,200,255), 0
GUI Spinbox sb_bright,              210, 210, 110, 25, , , 10, 10, 100
CtrlVal(sb_bright) = 100

' =================================================================
' Main loop: keyboard fallback for builds with no touch and no mouse
'
' Touch and mouse events go straight to TouchDown / TouchUp via the
' GUI interrupt, so nothing here has to handle them. The loop only
' translates keys into cursor moves and synthetic clicks:
'
'   arrow keys -- move the soft cursor stepx px
'   SPACE      -- momentary click at the current cursor
'   D / d      -- press-and-hold (useful for drag tests)
'   U / u      -- release a held click
'   ESC / Q    -- quit cleanly
' =================================================================
held = 0
Do
 k$ = Inkey$
 If k$ <> "" Then
   Select Case Asc(k$)
     Case &H82                       ' LEFT
       mx = mx - stepx
     Case &H83                       ' RIGHT
       mx = mx + stepx
     Case &H80                       ' UP
       my = my - stepx
     Case &H81                       ' DOWN
       my = my + stepx
     Case 32                         ' SPACE -- momentary click
       GUI Click mx, my
     Case 100, 68                    ' 'd' / 'D' -- press and hold
       If held = 0 Then
         GUI Cursor mx, my
         GUI Click Down
         held = 1
       EndIf
     Case 117, 85                    ' 'u' / 'U' -- release
       If held = 1 Then
         GUI Click Up
         held = 0
       EndIf
     Case 27, 113, 81                ' ESC / 'q' / 'Q' -- quit
       Exit Do
   End Select

   ' Keep the cursor inside the visible canvas.
   If mx < 0      Then mx = 0
   If my < 0      Then my = 0
   If mx > cw - 1 Then mx = cw - 1
   If my > ch - 1 Then my = ch - 1
   GUI Cursor mx, my
 EndIf
 Pause 5
Loop

' Drop any held click so we don't leave a phantom press behind.
If held = 1 Then GUI Click Up
GUI Cursor Off
End

' =================================================================
' Interrupt handlers
'
' Called for every input source: a finger on the touch panel, a mouse
' button via GUI CURSOR LINK MOUSE, or GUI CLICK from the keyboard
' fallback above. Touch(REF) holds the control that was hit; the body
' of each Case is the actual application logic for that control.
' =================================================================
Sub TouchDown
 Local Integer tx, ty
 tx = Touch(x) : ty = Touch(y)
 If Not (tx = -1 Or ty = -1) Then
   ' Real touch -- sync the soft cursor so it follows the finger.
   GUI Cursor tx, ty
   mx = tx : my = ty
 EndIf

 Select Case Touch(REF)
   Case cb_enabled                   ' enable / disable the logging UI
     If CtrlVal(cb_enabled) Then
       GUI Restore c_fname, tb_fname, c_log, cb_flow, cb_alarm, cb_warn
     Else
       GUI Disable c_fname, tb_fname, c_log, cb_flow, cb_alarm, cb_warn
     EndIf
   Case sb_bright                    ' brightness spinbox
     Backlight CtrlVal(sb_bright)
   Case sw_pmp                       ' pump on/off switch
     CtrlVal(led_run) = CtrlVal(sw_pmp)
     CtrlVal(tb_flow) = Str$(CtrlVal(sw_pmp) * 20.1)
     CtrlVal(r_norm)  = 1            ' snap power mode back to Normal
   Case pb_test                      ' alarm-test button (LED on while held)
     CtrlVal(led_alarm) = 1
   Case r_econ
     CtrlVal(tb_flow) = Str$(CtrlVal(sw_pmp) * 18.3)
   Case r_norm
     CtrlVal(tb_flow) = Str$(CtrlVal(sw_pmp) * 20.1)
   Case r_hi
     CtrlVal(tb_flow) = Str$(CtrlVal(sw_pmp) * 23.7)
 End Select
End Sub

Sub TouchUp
 Select Case Touch(LASTREF)
   Case pb_test                      ' release: turn the alarm LED off
     CtrlVal(led_alarm) = 0
 End Select
End Sub
 
phil99

Guru

Joined: 11/02/2018
Location: Australia
Posts: 3229
Posted: 10:28am 24 May 2026
Copy link to clipboard 
Print this post

This will keep many playing till late!

The tables in code boxes.
| Input device           | Mechanism                                                |
| ---------------------- | -------------------------------------------------------- |
| Touch screen           | `GUI INTERRUPT TouchDown, TouchUp`                       |
| Mouse (USB HID or PS/2)| `GUI CURSOR LINK MOUSE`                                  |
| Keyboard               | `INKEY$` loop driving `GUI CURSOR` and `GUI CLICK`       |

| Build                                | GUI controls | Touch | Mouse               | Keyboard      |
| ------------------------------------ | :----------: | :---: | ------------------- | ------------- |
| PicoMite **PICO** (RP2040 LCD)       |     yes      |  yes  | PS/2                | PS/2          |
| PicoMite **PICOUSB** (RP2040 LCD)    |     yes      |  yes  | USB HID             | USB HID       |
| PicoMite **PICORP2350**              |     yes      |  yes  | PS/2                | PS/2          |
| PicoMite **PICOUSBRP2350**           |     yes      |  yes  | USB HID             | USB HID       |
| PicoMiteVGA **VGARP2350**            |     yes      |   —   | PS/2                | PS/2          |
| PicoMiteVGA **VGAUSBRP2350**         |     yes      |   —   | USB HID             | USB HID       |
| PicoMiteHDMI **HDMI**                |     yes      |   —   | PS/2                | PS/2          |
| PicoMiteHDMI **HDMIUSB**             |     yes      |   —   | USB HID             | USB HID       |
| WebMite **WEBRP2350** (with LCD)     |     yes      |  yes  | PS/2                | PS/2          |
| PicoMiteBT **PICOBTRP2350**          |     yes      |  yes  | PS/2                | PS/2 + BT HID |
| PicoMiteBT **PICOBTHRP2350**         |     yes      |  yes  | USB HID             | USB HID + BT  |
| WebMite **WEB** (RP2040)             |    **no**    |   —   | —                   | —             |
| PicoMiteVGA **VGA** / **VGAUSB** (RP2040) | **no**  |   —   | —                   | —             |
| PicoMite **PICOMIN**                 |    **no**    |   —   | —                   | —             |

| Key          | Action                                                   |
| ------------ | -------------------------------------------------------- |
| ← → ↑ ↓      | Move the soft cursor by `stepx` pixels (4 px)            |
| Space        | `GUI Click mx, my` — momentary press-release             |
| `D` / `d`    | `GUI Click Down` — start a held press                    |
| `U` / `u`    | `GUI Click Up` — release the held press                  |
| `Esc`/`Q`/`q`| Exit the program cleanly                                 |

| Widget       | Purpose in this demo                                  |
| ------------ | ----------------------------------------------------- |
| `Caption`    | Static labels (heading, "Pump", "Flow Rate", "Hi:" …) |
| `Switch`     | Pump ON / OFF                                         |
| `Displaybox` | Read-only flow-rate value                             |
| `Frame`      | Visual grouping (Power, Alarm, Log File)              |
| `Radio`      | Power mode: Economy / Normal / High                   |
| `Numberbox`  | Editable Hi and Lo alarm thresholds                   |
| `Button`     | Momentary "TEST" alarm                                |
| `LED`        | Status indicators ("Running", "Alarm")                |
| `Checkbox`   | Logging enable + per-event filters                    |
| `Textbox`    | Log file name                                         |
| `Spinbox`    | Back-light percentage                                 |

+-----------+--------+--------------+
| Pump      | LEDs   | Log File     |
| Switch    | Run    | [x] Log On   |
|           | Alarm  | File Name    |
| Flow Rate |        | LOGFILE.TXT  |
|  20.1     | Alarm  |              |
|           | Hi: 35 | Record:      |
| Power     | Lo: 16 | [x] Flow     |
|  o Econ   | [TEST] | [x] Alarms   |
|  * Normal |        | [x] Warnings |
|  o High   |        |              |
|           |        | Back Light   |
|           |        | [- 100  +]   |
+-----------+--------+--------------+

Edited 2026-05-24 20:32 by phil99
 
toml_12953
Guru

Joined: 13/02/2015
Location: United States
Posts: 644
Posted: 10:39am 24 May 2026
Copy link to clipboard 
Print this post

  matherp said  V6.03.00RC12
PicoMiteRP2040V6.03.00RC12.zip
PicoMiteRP2350V6.03.00RC12.zip
Fixes bug in For loops introduced as part of optimisations
Finalises GUI controls to be completely flexible touch/no-touch, mouse/no-mouse, external contol keyboard/joystick etc.
Note: Geoff authored the gui controls and they now work in almost every MMbasic environment. All I have done is integrated them into the PicoMite codeset in a way that hopefully makes them more useful in many different scenarios.


Thanks for that! I have a few questions, though.

On PicoCalc, the pointer leaves a trail. Is that a problem with the demo program or PicoCalc?

I can't change the Flow Rate.

Pressing TEST changes nothing. Should the alarm light come on?

I can change the backlight control but neither the display nor the keyboard changes in brightness although both have backlights on PicoCalc.
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 11367
Posted: 11:16am 24 May 2026
Copy link to clipboard 
Print this post

The test and flow rate work if you use D and U
pointer trail shouldn't happen if the screen framebuffer is being read properly. Does PicoCalc properly wire the screen MISO and is it properly configured in the options?
To change the backlight you would need to change he code to match whatever the correct Basic calls are to do it.
I'm testing on a SSD1963_5_BUFF and everything works as expected.
Edited 2026-05-24 21:18 by matherp
 
matherp
Guru

Joined: 11/12/2012
Location: United Kingdom
Posts: 11367
Posted: 02:12pm 24 May 2026
Copy link to clipboard 
Print this post

Minor re-compile to fix gui click not triggering the MMBasic down/up interrupts

PicoMiteRP2040V6.03.00RC12.zip

PicoMiteRP2350V6.03.00RC12.zip

Here is the manual entry for the new code
GUI CURSOR

The GUI CURSOR command displays and manipulates a soft cursor on
the screen. The cursor sits above all other graphics — nothing can
overwrite it.

GUI CURSOR ON [cursorno [, x, y [, cursorcolour] ] ]
 Turns the cursor on. cursorno can be 0 (the default — a mouse-type
 pointer) or 1 (a cross). The user can load their own cursor using a
 Maximite-format sprite file (see GUI CURSOR LOAD below), in which
 case this is cursor number 2. For cursor numbers 0 and 1 the
 programmer can override the default white cursor by specifying a
 colour.

GUI CURSOR x, y
 Moves the cursor to x, y. Updates the stored position even when the
 cursor is currently hidden.

GUI CURSOR OFF
 Turns off the cursor and removes it from the screen.

GUI CURSOR HIDE
 Hides the cursor but retains its stored position.

GUI CURSOR SHOW
 Re-displays a hidden cursor at its stored position.

GUI CURSOR COLOUR cursorcolour
 Changes the colour of cursor number 0 or 1. Has no effect on a
 cursor loaded from a sprite file (those carry their own colours).

GUI CURSOR LOAD "fname"
 Loads a user cursor from a file in the Maximite sprite format with
 a minor change. The header is Width, Height, Xoffset, Yoffset. The
 two offsets define the pointer hot-spot — the mouse cursor has
 offsets 0,0 and the cross has offsets 7,7.

GUI CURSOR LINK MOUSE
GUI CURSOR UNLINK MOUSE
 Links and unlinks mouse activity to the cursor. When linked the
 cursor automatically tracks the mouse, whether the mouse is USB HID
 or PS/2. LINK MOUSE raises "No mouse connected" if no mouse is
 currently attached.


GUI CLICK

The GUI CLICK command synthesises a click event in the GUI CONTROLS
hit-test pipeline. The same pipeline drives real touch and real
mouse clicks, so the affected control's state, any value returned by
the CLICK() / TOUCH() functions and any routine armed with GUI
INTERRUPT all see a synthesised click exactly the same way they see
a real one.

GUI CLICK [x, y]
 Performs a momentary press-release click. With no arguments the
 click lands at the cursor's current position; with x, y the cursor
 is first moved to (x, y) and then clicked. The command blocks for
 approximately 130 ms — long enough for the down edge and the up
 edge to propagate through the hit-test and for any GUI INTERRUPT
 routine to run between them. If a GUI INTERRUPT fires during the
 wait the executor runs it immediately and resumes GUI CLICK on
 return, so user-supplied TouchDown and TouchUp routines are called
 in the correct order.

GUI CLICK DOWN
 Latches a press-and-hold at the cursor's current position. The
 button stays "down" until a matching GUI CLICK UP. This is the
 form to use for drag operations, or for binding to a physical
 button whose duration the user controls.

GUI CLICK UP
 Releases a previous GUI CLICK DOWN. Has no effect if no down is
 pending.

GUI CLICK PIN pin [, INV]
GUI CLICK PIN OFF
 Designates a physical input pin as a hardware click source. The
 pin is polled by the mS-timer ISR alongside the touch IRQ pin and
 the mouse left button, so a press on the pin is treated identically
 to a real touch or mouse click. Coordinates for the click are
 taken from the soft cursor (see GUI CURSOR), wherever the program
 has steered it. This is intended for joystick fire-buttons or
 similar physical switches on builds that have no touch panel and
 no mouse.

 pin must currently be unconfigured. The command claims it as a
 digital input with an internal pull:
   default polarity   active-low  (idle pulled up,   pressed reads 0)
   , INV              active-high (idle pulled down, pressed reads 1)

 Only one click pin may be assigned at a time; GUI CLICK PIN OFF
 must be issued first to re-assign. The pin is also released
 automatically on NEW, RUN and similar resets.


MsgBox() and emulated click sources

MsgBox() blocks the BASIC main loop while waiting for the user to
press one of its buttons. If the click that triggered the call into
MsgBox() came from GUI CLICK (synthetic) or GUI CLICK PIN, the user
has no way to steer the cursor over the popup's buttons — the
joystick, keyboard or pin handler that moves the cursor all live in
the suspended main loop. To avoid a silent deadlock, MsgBox()
refuses to open in that case and raises:

 MsgBox needs a real touch or mouse — cursor cannot be steered
 while MsgBox is open

Programs that call MsgBox() must therefore have a real touch panel
or a real mouse as the input device for any path that opens a
MsgBox.


Update demo code - demoing msgbox with click/pin handling

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Pump-control GUI demo for MMBasic builds with GUI CONTROLS
' -----------------------------------------------------------------
' Demonstrates the standard GUI widgets (caption, switch, displaybox,
' frame, radio, numberbox, button, LED, checkbox, textbox, spinbox)
' driven by whichever input methods the firmware happens to expose:
'
'   Touch screen .... via GUI INTERRUPT TouchDown, TouchUp
'   USB mouse ....... via GUI CURSOR LINK MOUSE
'   Keyboard ........ via INKEY$ + GUI CURSOR / GUI CLICK
'
' All three routes end up in the same TouchDown / TouchUp subs, so the
' program contains no per-input-source branching: each control is
' handled once, regardless of where the click came from.
'
' Layout is hand-placed for a 320x240 canvas so the program runs on
' the smallest LCD panels; on VGA/HDMI builds the program switches to
' MODE 2 (320x240) to keep the layout intact.
'
' Geoff Graham, October 2015 (original)
' Modified for ILI9341 by Phil23
' Refactored for multi-firmware input by Peter Mather, 2026
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Option Explicit

' ----- control reference numbers ---------------------------------
Const c_head     = 1,  c_pmp     = 2,  sw_pmp    = 3
Const c_flow     = 4,  tb_flow   = 5
Const led_run    = 6,  led_alarm = 7
Const frm_alarm  = 20, nbr_hi    = 21, nbr_lo    = 22, pb_test = 23
Const c_hi       = 24, c_lo      = 25
Const frm_pump   = 30, r_econ    = 31, r_norm    = 32, r_hi    = 33
Const frm_log    = 40, cb_enabled= 41, c_fname   = 42, tb_fname= 43
Const c_log      = 44, cb_flow   = 45, cb_pwr    = 46, cb_warn = 47
Const cb_alarm   = 48, c_bright  = 49, sb_bright = 50

' ----- layout constants ------------------------------------------
Const ledsX = 125              ' x column shared by both LEDs
Const stepx = 4                ' keyboard cursor step in pixels

' ----- runtime state ---------------------------------------------
Dim Integer cw, ch             ' canvas width / height
Dim Integer mx, my             ' soft-cursor position
Dim Integer ledsY              ' running y while stacking the LEDs
Dim Integer held               ' 1 while GUI CLICK DOWN is in effect
Dim String  k$

' =================================================================
' Display + input device setup
' =================================================================
Colour RGB(white), RGB(black)
CLS

' VGA/HDMI firmware boots in a larger mode; force 320x240 so the
' hard-coded coordinates below land in the right place.
If Instr(MM.DEVICE$, "VGA") Or Instr(MM.DEVICE$, "HDMI") Then
 MODE 2
EndIf

cw = MM.HRES : ch = MM.VRES
mx = cw \ 2  : my = ch \ 2

' The soft cursor is required for mouse and keyboard input. Touch-only
' firmware accepts the command and simply never moves the cursor.
GUI Cursor On

' GUI CURSOR LINK MOUSE only exists on builds with USB host support.
' "On Error Skip" lets older firmware silently continue.
On Error Skip
GUI Cursor Link Mouse
GUI click pin gp2
' Both real touches and GUI CLICK (used by the keyboard fallback)
' dispatch through this interrupt pair.
GUI Interrupt TouchDown, TouchUp

' =================================================================
' Build the pump-control display
' =================================================================

' --- heading and pump label --------------------------------------
Font 2
GUI Caption c_head, "Pump Control", 10, 0
GUI Caption c_pmp,  "Pump",         10, 25, , RGB(brown)

' --- pump ON/OFF switch ------------------------------------------
GUI Switch sw_pmp, "ON|OFF", 10, 45, 70, 30, RGB(white), RGB(brown)
CtrlVal(sw_pmp) = 1                                  ' starts ON

' --- flow-rate read-out ------------------------------------------
GUI Caption    c_flow,  "Flow Rate", 5, 75,  , RGB(brown), 0
GUI Displaybox tb_flow,              5, 100, 105, 25
CtrlVal(tb_flow) = "20.1"

' --- power-mode radio group --------------------------------------
GUI Frame frm_pump, "Power", 5, 140, 105, 90, RGB(200,20,255)
Font 1
GUI Radio r_econ, "Economy", 20, 160, 10, RGB(230,230,255)
GUI Radio r_norm, "Normal",  20, 185
GUI Radio r_hi,   "High",    20, 210
CtrlVal(r_norm) = 1                                  ' default mode

' --- alarm frame: Hi/Lo number boxes + TEST button ---------------
Font 2 : GUI Frame frm_alarm, "Alarm", 115, 115, 90, 115, RGB(green)
Font 1
GUI Caption   c_hi,    "Hi:", 120, 150, LT, RGB(yellow)
GUI Numberbox nbr_hi,         150, MM.VPOS-6, 40, MM.FONTHEIGHT+6, RGB(yellow), RGB(64,64,64)
GUI Caption   c_lo,    "Lo:", 120, 175, LT, RGB(yellow), 0
GUI Numberbox nbr_lo,         150, MM.VPOS-6, 40, MM.FONTHEIGHT+6, RGB(yellow), RGB(64,64,64)
GUI Button    pb_test, "TEST", 125, 200, 70, 25, RGB(yellow), RGB(red)
CtrlVal(nbr_hi) = 35.5
CtrlVal(nbr_lo) = 15.7

' --- two status LEDs, stacked vertically -------------------------
ledsY = 50         : GUI LED led_run,   "Running", ledsX, ledsY, 8, RGB(green)
ledsY = ledsY + 25 : GUI LED led_alarm, "Alarm",   ledsX, ledsY, 8, RGB(red)
CtrlVal(led_run) = 1                                 ' tracks the switch

' --- logging frame: enable, file name, per-event check boxes -----
Colour RGB(cyan), 0
GUI Frame    frm_log,    "Log File",  210, 10,  110, 160, RGB(green)
GUI Checkbox cb_enabled, "Log On",    215, 20,  20, RGB(cyan)
GUI Caption  c_fname,    "File Name", 215, 45
GUI Textbox  tb_fname,                215, 60,  100, 20, RGB(cyan), RGB(64,64,64)
GUI Caption  c_log,      "Record:",   215, 85,  , RGB(cyan), 0
GUI Checkbox cb_flow,    "Flow",      220, 100, 20
GUI Checkbox cb_alarm,   "Alarms",    220, 120, 20
GUI Checkbox cb_warn,    "Warnings",  220, 140, 20
CtrlVal(cb_enabled) = 1
CtrlVal(tb_fname)   = "LOGFILE.TXT"

' --- backlight spinbox -------------------------------------------
GUI Caption c_bright, "Back Light", 230, 190, , RGB(200,200,255), 0
GUI Spinbox sb_bright,              210, 210, 110, 25, , , 10, 10, 100
CtrlVal(sb_bright) = 100

' =================================================================
' Main loop: keyboard fallback for builds with no touch and no mouse
'
' Touch and mouse events go straight to TouchDown / TouchUp via the
' GUI interrupt, so nothing here has to handle them. The loop only
' translates keys into cursor moves and synthetic clicks:
'
'   arrow keys -- move the soft cursor stepx px
'   SPACE      -- momentary click at the current cursor
'   D / d      -- press-and-hold (useful for drag tests)
'   U / u      -- release a held click
'   ESC / Q    -- quit cleanly
' =================================================================
held = 0
Do
 k$ = Inkey$
 If k$ <> "" Then
   Select Case Asc(k$)
   Case &H82                       ' LEFT
     mx = mx - stepx
   Case &H83                       ' RIGHT
     mx = mx + stepx
   Case &H80                       ' UP
     my = my - stepx
   Case &H81                       ' DOWN
     my = my + stepx
   Case 32                         ' SPACE -- momentary click
'      GUI cursor mx, my
'      GUI click down
'      Pause 10
'      GUI click up
     GUI click mx,my
   Case 100, 68                    ' 'd' / 'D' -- press and hold
     If held = 0 Then
       GUI Cursor mx, my
       GUI Click Down
       held = 1
     EndIf
   Case 117, 85                    ' 'u' / 'U' -- release
     If held = 1 Then
       GUI Click Up
       held = 0
     EndIf
   Case 27, 113, 81                ' ESC / 'q' / 'Q' -- quit
     Exit Do
   End Select

   ' Keep the cursor inside the visible canvas.
   If mx < 0      Then mx = 0
   If my < 0      Then my = 0
   If mx > cw - 1 Then mx = cw - 1
   If my > ch - 1 Then my = ch - 1
   GUI Cursor mx, my
 EndIf
 Pause 5
Loop

' Drop any held click so we don't leave a phantom press behind.
If held = 1 Then GUI Click Up
GUI Cursor Off
End

' =================================================================
' Interrupt handlers
'
' Called for every input source: a finger on the touch panel, a mouse
' button via GUI CURSOR LINK MOUSE, or GUI CLICK from the keyboard
' fallback above. Touch(REF) holds the control that was hit; the body
' of each Case is the actual application logic for that control.
' =================================================================
Sub TouchDown
 Local Integer tx, ty,mbox
 tx = Touch(x) : ty = Touch(y)
 If Not (tx = -1 Or ty = -1) Then
   ' Real touch -- sync the soft cursor so it follows the finger.
   GUI Cursor tx, ty
   mx = tx : my = ty
 EndIf
 Select Case Touch(REF)
 Case cb_enabled                   ' enable / disable the logging UI
   If CtrlVal(cb_enabled) Then
     GUI Restore c_fname, tb_fname, c_log, cb_flow, cb_alarm, cb_warn
   Else
     mbox=1
     On error skip
     mbox=MsgBox("Are you sure?", "YES","CANCEL")
     If mbox=1 Then
       GUI Disable c_fname, tb_fname, c_log, cb_flow, cb_alarm, cb_warn
     Else
       CtrlVal(cb_enabled)=1
     EndIf
   EndIf
 Case sb_bright                    ' brightness spinbox
   Backlight CtrlVal(sb_bright)
 Case sw_pmp                       ' pump on/off switch
   CtrlVal(led_run) = CtrlVal(sw_pmp)
   CtrlVal(tb_flow) = Str$(CtrlVal(sw_pmp) * 20.1)
   CtrlVal(r_norm)  = 1            ' snap power mode back to Normal
 Case pb_test                      ' alarm-test button (LED on while held)
   CtrlVal(led_alarm) = 1
 Case r_econ
   CtrlVal(tb_flow) = Str$(CtrlVal(sw_pmp) * 18.3)
 Case r_norm
   CtrlVal(tb_flow) = Str$(CtrlVal(sw_pmp) * 20.1)
 Case r_hi
   CtrlVal(tb_flow) = Str$(CtrlVal(sw_pmp) * 23.7)
 End Select
End Sub

Sub TouchUp
 Select Case Touch(LASTREF)
 Case pb_test                      ' release: turn the alarm LED off
   CtrlVal(led_alarm) = 0
 End Select
End Sub
 
     Page 11 of 12    
Print this page
The Back Shed's forum code is written, and hosted, in Australia.
© JAQ Software 2026