TFT and GUI examples

Place code snippets and demo code here
Post Reply
User avatar
Electroguard
Posts: 835
Joined: Mon Feb 08, 2021 6:22 pm
Has thanked: 267 times
Been thanked: 317 times

TFT and GUI examples

Post by Electroguard »

CiccioCB previously created lots of example scripts to demonstrate use of TFT GUI objects, but collectively the graphics for the backgrounds and icons etc are too big for them to all fit in the firmware data zips, so there are actually not many examples currently publicly available at the moment.
That's what this topic is for... a place where the TFT and GUI examples can be published and made available - therefore most of the gui examples will soon be published here as a zip which will include the img and icons folders, after finishing testing for old syntax etc,
This will allow them all to be uploaded to SD in their entirety, or selectively uploaded along with their required graphics.

And of course this could also be a handy place for anybody else to post up any other TFT and GUI examples.
So to get the ball rolling (literally) here is a TFT guiXYball example to demonstrate dual-axis sliders for controlling X and Y axis of Pan & Tilt etc.

guiptball.jpg

Quick slider demo vid... https://youtu.be/PCn1dCwmRWE

The script comments explain how to change from 320 * 240 (default) to 4" 480 * 320 (or other sizes for that matter).
Anything important uses variables for easy 'top-of-the-script' changes, rather than having hard-coded values embedded throughout.
So feel free to experiment with the effects of changing object sizes etc to better suit different screen sizes and orientations.

Some of the variables such as "speed" and xdir and ydir (direction flags) are only needed for an irrelevant ''bouncing ball' triviality and can be removed along with the "paint" branch.

Quick bouncing ball demo... https://youtu.be/mtkn9d4eLOc

Code: [Local Link Removed for Guests]

'GUI Pan & Tilt demo - Electroguard - developed on Annex32 1.43.5
'Originally intended as X and Y axis slider and progress bar demo for 320 * 240 TFT touchscreen 
'Uses variables so that most aspects can be easily changed, eg: for 4" TFT set xres=480 and yres=320
'Sliders can be Dragged & Dropped, or touched anywhere on their line to jump there
'Added a moving dot just to illustrate an example of dual axis control
'Got bored with the dot, so made it a pointless bouncing ball just for the hell of it (un-comment 'timer0 100, paint)
'touch.calib           'only needs doing once if TFT screen or orientation is changed            '
gui.init 10, 0
xres=320: yres=240     'TFT screen size
speed=15               'bouncing ball speed if timer is enabled
xdir=1: ydir=1         'direction of bouncing ball 0=reducing, 1=increasing
xmag=2.2: ymag=1.4     'x & y scaling factors
xcentre = xres/2 : ycentre = yres/2: '
x=xcentre: y=ycentre   'centre of screen
dia=10: colour=tft.rgb(0,255,0)  'set dot size and colour
tft.circle x, y, dia, colour, 1
sh=36            'slider button height (gui.setstyle uses different scaling so has been hardcoded) 
st=sh            'slider tick size
sm=sh/2          'slider margin
s1w=220          'width (length) of x axis slider, can be increased or decreased as wished          
s1x=(xres/2)-(s1w/2)
s1y=yres-sh
sld1=gui.slider s1x, s1y, s1w, sh, 50, 0
gui.setEvent sld1, 3, slider1
Gui.SetStyle sld1, 14, 1, 10
s2w=160          'width (length) of y axis slider, can be increased or decreased as wished      
s2x=xres-sh
s2y=(yres/2)-(s2w/2)
sld2=gui.slider s2x, s2y, sh, s2w, 50, 1
gui.setEvent sld2, 3, slider2
Gui.SetStyle sld2, 14, 1, 10
ph=24            'slider button height
pm=4             'progress bar margin
p1w=150           
p1x=(xres/2)-(p1w/2)
p1y=pm
prg1=gui.progressbar p1x, p1y, p1w, ph, 50, 0
p2w=110           
p2x=pm
p2y=(yres/2)-(p2w/2)
gui.setcolor prg1, tft.rgb(255,255,0),0
prg2=gui.progressbar p2x, p2y, ph, p2w, 50, 1
gui.setcolor prg2, tft.rgb(0,255,250),0
gui.autorefresh 10,1
'timer0 100, paint     'un-comment this line for a pointless bouncing ball
wait

paint:
frame=30+dia        'frame border
tft.circle x, y, dia, 0, 1
if xdir=1 then
 if x+speed < (xres-frame) then x=x+speed else xdir=0
endif
if xdir=0 then
 if x-speed > frame then x=x-speed else xdir=1
endif
if ydir=1 then
 if y+speed < (yres-frame) then y=y+speed else ydir=0 
endif
if ydir=0 then 
 if y-speed > frame then y=y-speed else ydir=1 
endif
tft.circle x, y, dia, colour, 1
return

slider1:
tft.circle x, y, dia, 0, 1
x = (gui.getvalue(sld1) * xmag) + xcentre - (50 * xmag)
tft.circle x, y, dia, colour, 1
gui.setvalue prg1, gui.getvalue sld1
'wlog x
return

slider2:
tft.circle x, y, dia, 0, 1
y = yres - ((gui.getvalue(sld2) * ymag) + ycentre - (50 * ymag))
tft.circle x, y, dia, colour, 1
gui.setvalue prg2, gui.getvalue sld2
'wlog y
return

end
You do not have the required permissions to view the files attached to this post.
BeanieBots
Posts: 315
Joined: Tue Jun 21, 2022 2:17 pm
Location: South coast UK
Has thanked: 168 times
Been thanked: 102 times

Analogue Clock

Post by BeanieBots »

This is a simple little routine to demonstrate the use of GUI gauges for the hands of the clock.
I tried to implement some other GUI functions but unfortunately, because the gauge does an 'undraw' when it updates, to get the clock hands to sit on top of each other, it is necessary to do a double refesh which causes flicker on the other controls.

There are ten example clock faces. Some use jpg files (hopefully attached below, which need to be loaded into the root folder) and the others are drawn old-school.
I've included an annoying routine to cycle through each example every 15 seconds. Just knock out the TIMER1 line to stop it.
It is primarily aimed as being a demo of setting gauge angles (annex uses radians, not degrees) but, some fairly sweet clock faces as well.
They were created in the open source graphics package GIMP. Not for the faint hearted but a very powerful graphics package. Check it out.
Edit: Minor bug now fixed.

Code: [Local Link Removed for Guests]

'****************************************************************************
'*                                                                          *
'*             Analogue Clock  by BeanieBots July 2022                      *
'*                                                                          *
'*    Optimised for TFT screens with a resolution of 240x320                *
'*    Tested on ESP32 with Annex32 WiFi BLE CAN 1.44.2 firmware             *
'*    TO DO - Add compensation for different text fonts (only 4 supported)  *
'*    V1.0.0 15/07/2022  Added user defineable examples                     *
'*    V1.0.1 16/07/2022  Covnerted main text from tft.print to tft.draw     *
'*    V1.0.2 16/07/2022  A little tidy up before posting                    *
'*                                                                          *
'*        Please try out all the examples & some yourself.                  *
'*                                                                          *
'****************************************************************************

Example = 1                'There are 10 example setups
Example_old = Example

Gosub Declarations         'Configure the text values for days & months
Gosub DefaultValues        'Ensure ALL variables are set
Gosub UserPrefs            'Override defaults as required
Gosub Initialise           'Set everything up ready to go.
Gosub DrawFace             'Draw the clock face.
Timer0 1000, Update_Clock  'Print & draw current values every second

Timer1 15000, ChangeExample'Delete this line to stop cycling the examples

wait
'###########################################################################
ChangeExample:              'Delete this entire section   ^
Example = Example + 1       'once you have observed all   |
If Example > 10 then         'the different examples       |
  Example = 1               '                             |
EndIf                       '                             |
Return                      '                             v
'###########################################################################
Update_Clock:
'--------------------------------------------------------------------
  If Example_Old <> Example then   '
    Gosub DefaultValues            '  
    Gosub UserPrefs                '  
    Gosub Initialise               ' 
    Gosub Drawface                 '
    Example_Old = Example          '
  EndIF                            '
'--------------------------------------------------------------------
  tft.text.col Col_Text,Col_Back
  DoW = (dateunix(Date$)) mod 7  
  TFT.TEXT.ALIGN 1        'ALIGN_TOP_MID
  TFT.TEXT.PADDING 150
  tft.text.draw Day$(Dow),120,0,4
  
  secs = val(mid$(time$,7,2))+30 mod 59
  mins = val(mid$(time$,4,2))+30 mod 59
  Hrs = (val(mid$(time$,1,2)))*5+28 +(mins/14) mod 59
  Month = Val(mid$(date$,4,2))
  Day = Val(mid$(date$,1,2))

  TFT.TEXT.ALIGN 8       'ALIGN_BOT_RIGHT
  TFT.TEXT.PADDING 80
  TFT.TEXT.DRAW Month$(Month)+" "+str$(Day),90,57,4
  
  Select Case Day        'Calculate the Ordinal Suffix
    Case 1:             OS$ = "st"
    Case 2:             OS$ = "nd"
    Case 3:             OS$ = "rd"
    Case 4 to 20:       OS$ = "th"
    Case 21:            OS$ = "st"
    Case 22:            OS$ = "nd"
    Case 23:            OS$ = "rd"
    Case 24 to 30:      OS$ = "th"
    Case 31:            OS$ = "st"
    Case Else:          OS$ = "  "
  End Select
  
  tft.text.font 2
  tft.text.pos 93,28
  tft.print OS$;" "
  
  tft.text.align 7      'ALIGN_BOT_MID
  tft.text.padding 70
  tft.text.draw "20"+right$(date$,2),175,57,4
  
  tft.text.align 7      'ALIGN_BOT_MID
  tft.text.padding 115
  tft.text.draw time$,120,320,4
  
  secs = val(mid$(time$,7,2))+30 mod 59
  mins= val(mid$(time$,4,2))+30 mod 59  
  Hrs = (val(mid$(time$,1,2)))*5+28 +(mins/14) mod 59'[min/19.2]

  Gui.SetValue Hand_H, hrs
  Gui.SetValue Hand_M, mins
  Gui.SetValue Hand_S, secs
  
  gui.redraw
  gui.redraw  '2nd redraw required to tidy up hands below second hand.
  tft.circle x,y,7,tft.rgb(0,0,0),1
  tft.circle x,y,3,tft.rgb(255,255,255),0

Return
'###############################################################################
DrawFace:

If Filename$ <> "" then

  TFT.JPG FileName$, x-120,y-120,0
  
 Else  'It needs to be drawn the old fashioned way!

  tft.text.font FaceFont
  S_Arc = FaceSize * 0.89-TickLength-(Padsize/2.1)
  tft.circle x, y , FaceSize,Col_ring,1
  tft.circle x, y , (FaceSize-TickLength-2),Col_Face,1
  For N = 0 to 59 step 5
    A=2*Pi*N/60
    X1=cos(A) * S_Arc+x
    Y1=sin(A) * S_Arc+y
    tft.circle x1, y1 , PadSize, Col_Face_Back, 1  
    H$=str$(int((n/5)+2) MOD 12 + 1)
    tft.text.pos X1+TextCompX-(len(H$)*TextCompS),Y1-TextCompY
    tft.text.col Col_Digit,Col_Face_Back
    tft.print H$ 
  Next N
  
  S_Arc = FaceSize * 0.99

  TS=0.005  'Small tick angle
  
  For Z = -TS to TS step 0.001
    For N = 0 to 59 step 1
      A=2*Pi*N/60
      X1=cos(A+Z)  * (S_Arc)+x
      Y1=sin(A+Z)  * (S_Arc)+y
      X2=cos(A+Z)  * (S_Arc-TickLength)+x
      Y2=sin(A+Z)  * (S_Arc-TickLength)+y
      TFT.Line X1, Y1, X2, Y2, Col_Tick_Small
    Next N
  Next Z

  TS=0.02  'Large tick angle
  
  For Z = -TS to TS step 0.001
    For N = 0 to 59 step 5
      A=2*Pi*N/60
      X1=cos(A+Z)  * (S_Arc)+x
      Y1=sin(A+Z)  * (S_Arc)+y
      X2=cos(A+Z)  * (S_Arc-TickLength)+x
      Y2=sin(A+Z)  * (S_Arc-TickLength)+y
      TFT.Line X1, Y1, X2, Y2, Col_Tick_Large
    Next N
  Next Z
   
EndIF
Return
'###############################################################################
Declarations:
  Dim Day$(6)
  Day$(0)="Thursday"    
  Day$(1)="Wednesday"
  Day$(2)="Tuesday" 
  Day$(3)="Monday"
  Day$(4)="Sunday"  
  Day$(5)="Saturday"    
  Day$(6)="Friday"    

  Dim Month$(12)
  Month$(0) = "Err"
  Month$(1) = "Jan"
  Month$(2) = "Feb"
  Month$(3) = "Mar"
  Month$(4) = "Apr"
  Month$(5) = "May"
  Month$(6) = "Jun"
  Month$(7) = "Jul"
  Month$(8) = "Aug"
  Month$(9) = "Sep"
  Month$(10)= "Oct"
  Month$(11)= "Nov"
  Month$(12)= "Dec"
Return
'###############################################################################
Initialise:
Length_S = FaceSize - 30 - TickLength - FaceFont*3.9 + HandLengthAdjust
Length_M = Length_S * 0.93 'compensation for each clock hand length
Length_H = Length_M * 0.85 '
tft.init 0           'Force screen orientation
gui.init 3, Col_Face '(back colour does not appear to work so set in gui.gauge)
X=120                'Location for clock face center
Y=175
tft.brightness 240
tft.fill Col_Back
tft.text.font FaceFont
tft.text.pos 0,10
tft.text.col Col_Text,Col_Back

Select Case FaceFont
   Case 1
    TextCompS = 4   'X Scale
    TextCompX = 3   'X Offset
    TextCompY = 4   'Y Offset
    PadSize   = 10
   Case 2
    TextCompS = 5   'X Scale
    TextCompX = 3   'X Offset
    TextCompY = 8   'Y Offset
    PadSize   = 12
  Case 3
    TextCompS = 7.5 'X Scale
    TextCompX = 4   'X Offset
    TextCompY = 8   'Y Offset
    PadSize   = 16
  Case 4
    TextCompS = 8.5 'X Scale
    TextCompX = 3   'X Offset
    TextCompY = 11  'Y Offset
    PadSize   = 19      
  Case 5
    TextCompS = 9.5 'X Scale
    TextCompX = 3   'X Offset
    TextCompY = 11  'Y Offset
    PadSize   = 20     
  Case else
    FaceFont = 1
    TextCompS = 4   'X Scale
    TextCompX = 3   'X Offset
    TextCompY = 4   'Y Offset
    PadSize   = 10
End Select

Hand_H = GUI.Gauge(x, y, 0, 0, 0 ,Col_Hand_H ,Col_Face) 
Hand_M = GUI.Gauge(x, y, 0, 0, 0 ,Col_Hand_M ,Col_Face) 
Hand_S = GUI.Gauge(x, y, 0, 0, 0 ,Col_Hand_S ,Col_Face)
gui.setrange Hand_H, 0, 60
gui.setrange Hand_M, 0, 60
gui.setrange Hand_S, 0, 60
gui.setstyle Hand_H, Length_H,Width_H
gui.setstyle Hand_M, Length_M,Width_M
gui.setstyle Hand_S, Length_S,Width_S
Return
'###############################################################################
DefaultValues:
Filename$ = ""
FaceSize = 118
TickLength = 9
FaceFont = 2 '1,2,3 & 4 Only sizes valid
TextFont = 4
Width_S = 3
Width_M = 4
Width_H = 6
Col_Face = tft.rgb(64,196,64)
Col_Digit = tft.rgb(255,255,255)
Col_Back = tft.rgb(0,0,255)
Col_Text = tft.rgb(255,255,0)
Col_Face_Back = tft.rgb(0,0,0)
Col_Ring = tft.rgb(255,0,255)
Col_Hand_H = tft.rgb(32,255,32)
Col_Hand_M = tft.rgb(255,240,32)
Col_Hand_S = tft.rgb(255,64,0)
Col_Tick_Large = tft.rgb(255,255,255)
Col_Tick_Small = tft.rgb(128,128,128)
HandLengthAdjust = 0
Return
'###############################################################################
UserPrefs:
'You can fiddle here with values that are set as default above
'Please note, the hand lengths are a function of FaceSize
'If a filename is set, no face will be drawn, just the hands.
Select Case Example

  Case 1  'Very basic. Simplest is often best.
    Filename$ = "/Classic.jpg"
    FaceSize = 114
    Col_Back = tft.rgb(0,0,0)
    Col_Face = tft.rgb(0,0,0)
    Col_Text = tft.rgb(255,255,255)
    
  Case 2  'Thin font roman numerals
    Filename$ = "/Roman_I.jpg"
    FaceSize = 120
    Col_Back = tft.rgb(0,0,0)
    Col_Face = tft.rgb(0,0,0)
    Col_Text = tft.rgb(255,255,255)
  
  Case 3  'Larger roman numerals
    Filename$ = "/Roman_II.jpg"
    FaceSize = 112
    Col_Back = tft.rgb(0,0,0)
    Col_Face = tft.rgb(0,0,0)
    Col_Text = tft.rgb(96,128,255)
    
  Case 4  'A slightly fancier face.
    Filename$ = "/Fancy.jpg"
    FaceSize = 110
    Col_Back = tft.rgb(255,255,0)
    Col_Face = tft.rgb(255,255,0)
    Col_Text = tft.rgb(0,0,255)
    Col_Hand_H = tft.rgb(32,32,255)
    Col_Hand_M = tft.rgb(32,240,32)
    Col_Hand_S = tft.rgb(240,16,16)
    
  Case 5 'Classic Old school (My personal favourite)
    Filename$ = ""
    FaceSize = 118
    FaceFont = 4
    Col_Face = tft.rgb(0,0,0)
    Col_Digit = tft.rgb(255,255,255)
    Col_Back = tft.rgb(0,0,0)
    Col_Text = tft.rgb(255,255,0)
    Col_Face_Back = tft.rgb(0,0,0)
    Col_Ring = tft.rgb(64,64,196)
    Col_Hand_H = tft.rgb(32,255,32)
    Col_Hand_M = tft.rgb(255,240,32)
    Col_Hand_S = tft.rgb(255,64,0)
    Col_Tick_Large = tft.rgb(255,255,255)
    Col_Tick_Small = tft.rgb(0,0,0)
    HandLengthAdjust = 10
    
  Case 6 'A bigger brighter face
    Filename$ = ""
    FaceSize = 118
    FaceFont = 2
    Col_Face = tft.rgb(240,240,255)
    Col_Digit = tft.rgb(0,0,255)
    Col_Back = tft.rgb(255,255,128)
    Col_Text = tft.rgb(0,0,240)
    Col_Face_Back = tft.rgb(240,240,255)
    Col_Ring = tft.rgb(240,240,240)
    Col_Hand_H = tft.rgb(32,255,32)
    Col_Hand_M = tft.rgb(255,240,32)
    Col_Hand_S = tft.rgb(255,64,0)
    Col_Tick_Large = tft.rgb(0,0,0)
    Col_Tick_Small = tft.rgb(0,0,0)
    Col_Hand_M = tft.rgb(255,196,0)
    HandLengthAdjust = 10
    
  Case 7  'Hacker. Classic green screen.
    Filename$ = ""
    FaceSize = 85
    FaceFont = 3
    Col_Face = tft.rgb(0,0,0)
    Col_Digit = tft.rgb(0,255,0)
    Col_Back = tft.rgb(0,0,0)
    Col_Text = tft.rgb(0,255,0)
    Col_Face_Back = tft.rgb(0,0,0)
    Col_Ring = tft.rgb(0,128,0)
    Col_Hand_H = tft.rgb(32,196,32)
    Col_Hand_M = tft.rgb(64,196,64)
    Col_Hand_S = tft.rgb(128,240,64)
    Col_Tick_Large = tft.rgb(96,255,96)
    Col_Tick_Small = tft.rgb(0,255,0)
    TickLength = 4
    Width_S = 2
    Width_M = 3
    Width_H = 4
    HandLengthAdjust = 10
  
  Case 8  'Black on white. Small clock digits
    Filename$ = ""
    FaceSize = 100
    FaceFont = 1
    Col_Face = tft.rgb(255,255,255)
    Col_Digit = tft.rgb(0,0,0)
    Col_Back = tft.rgb(255,255,255)
    Col_Text = tft.rgb(0,64,0)
    Col_Face_Back = tft.rgb(255,255,255)
    Col_Ring = tft.rgb(196,196,196)
    Col_Hand_H = tft.rgb(64,64,64)
    Col_Hand_M = tft.rgb(96,96,96)
    Col_Hand_S = tft.rgb(240,128,128)
    Col_Tick_Large = tft.rgb(0,0,0)
    Col_Tick_Small = tft.rgb(255,255,255)
    TickLength = 3
    Width_S = 2
    Width_M = 3
    Width_H = 4
    HandLengthAdjust = 10
  
  Case 9 'As Small as realisticly possible
    Filename$ = ""
    FaceSize = 45
    FaceFont = 1
    Col_Face = tft.rgb(0,0,0)
    Col_Digit = tft.rgb(0,255,255)
    Col_Back = tft.rgb(0,0,0)
    Col_Text = tft.rgb(0,255,255)
    Col_Face_Back = tft.rgb(0,0,0)
    Col_Ring = tft.rgb(0,128,128)
    Col_Hand_H = tft.rgb(32,255,192)
    Col_Hand_M = tft.rgb(240,240,64)
    Col_Hand_S = tft.rgb(255,64,64)
    Col_Tick_Large = tft.rgb(255,255,255)
    Col_Tick_Small = tft.rgb(64,240,240)
    TickLength = 2
    Width_S = 2
    Width_M = 3
    Width_H = 4
    HandLengthAdjust = 18
    
  Case 10  'Clock face numbers drawn on pads
    Filename$ = ""
    FaceSize = 110
    TickLength = 11
    Col_Face = tft.rgb(96,96,192)
    Col_Digit = tft.rgb(0,0,0)
    Col_Back = tft.rgb(0,128,0)
    Col_Text = tft.rgb(255,255,0)
    Col_Face_Back = tft.rgb(255,255,64)
    Col_Ring = tft.rgb(255,96,255)
    Col_Hand_H = tft.rgb(32,255,32)
    Col_Hand_M = tft.rgb(255,240,32)
    Col_Hand_S = tft.rgb(255,64,0)
    Col_Tick_Large = tft.rgb(255,255,255)
    Col_Tick_Small = tft.rgb(128,128,96)
    HandLengthAdjust = 6
    
  Case Else
    'use purely default values
End Select
Example_Old = Example
Return
'###############################################################################

You do not have the required permissions to view the files attached to this post.
Last edited by BeanieBots on Sun Aug 14, 2022 10:01 am, edited 4 times in total.
User avatar
cicciocb
Site Admin
Posts: 1889
Joined: Mon Feb 03, 2020 1:15 pm
Location: Toulouse
Has thanked: 405 times
Been thanked: 1261 times
Contact:

Re: TFT and GUI examples

Post by cicciocb »

Very nice demo!!
Just tested on a ESP32-C3 that I'm actually testing and it works great out of the box!!

Thanks a lot.
1657998676922.jpg
1657998676956.jpg
1657998676889.jpg
You do not have the required permissions to view the files attached to this post.
BeanieBots
Posts: 315
Joined: Tue Jun 21, 2022 2:17 pm
Location: South coast UK
Has thanked: 168 times
Been thanked: 102 times

Re: TFT and GUI examples

Post by BeanieBots »

Doh, there's a bug. :oops:
The ordinal suffix is overlaid on the date for dates > 9 < 20.
I'll fix it and edit the code in the post when i get a little time to look into it.
Edit: This has now been fixed.
Post Reply