Onboarding and Guided Tour Module
Posted: Wed Feb 11, 2026 2:39 am
I wrote this for some of my apps. It lets you display an onboarding window that can have multiple steps that you can use to guide first time users on how to use your app or do things like ask for donations.
It is cross-platform. You define each steps using a list element. An example is included below. It also supports images though it is primarily for displaying text.
It is cross-platform. You define each steps using a list element. An example is included below. It also supports images though it is primarily for displaying text.
Code: Select all
DeclareModule Tour
Structure Screen
Title.s
Description.s
ImageHandle.i
EndStructure
Declare.i Start(List Screens.Screen(), ParentWindowID.i = 0)
EndDeclareModule
Module Tour
Structure State
WindowID.i
CurrentPage.i
TotalPages.i
List Screens.Screen()
TitleGadget.i
DescGadget.i
ImageGadget.i
BtnBack.i
BtnNext.i
ChkDismiss.i
Result.i
EndStructure
Procedure UpdateUI(*State.State)
SelectElement(*State\Screens(), *State\CurrentPage)
SetGadgetText(*State\TitleGadget, *State\Screens()\Title)
SetGadgetText(*State\DescGadget, *State\Screens()\Description)
If *State\Screens()\ImageHandle <> -1 And IsImage(*State\Screens()\ImageHandle)
SetGadgetState(*State\ImageGadget, ImageID(*State\Screens()\ImageHandle))
HideGadget(*State\ImageGadget, #False)
ResizeGadget(*State\DescGadget, 20, 200, 360, 80)
Else
HideGadget(*State\ImageGadget, #True)
ResizeGadget(*State\DescGadget, 20, 90, 360, 200)
EndIf
DisableGadget(*State\BtnBack, Bool(*State\CurrentPage = 0))
If *State\CurrentPage = *State\TotalPages - 1
SetGadgetText(*State\BtnNext, "Finish")
Else
SetGadgetText(*State\BtnNext, "Next")
EndIf
SetWindowTitle(*State\WindowID, "Onboarding Step " + Str(*State\CurrentPage + 1) + " of " + Str(*State\TotalPages))
EndProcedure
Procedure.i Start(List UserScreens.Screen(), ParentWindowID.i = 0)
Protected State.State
CopyList(UserScreens(), State\Screens())
State\TotalPages = ListSize(State\Screens())
If State\TotalPages = 0 : ProcedureReturn #False : EndIf
State\WindowID = OpenWindow(#PB_Any, 0, 0, 400, 380, #Empty$, #PB_Window_ScreenCentered, ParentWindowID)
StickyWindow(State\WindowID, #True)
LoadFont(10, "Arial", 24, #PB_Font_Bold)
State\TitleGadget = TextGadget(#PB_Any, 20, 20, 360, 26, #Empty$, #PB_Text_Center)
SetGadgetFont(State\TitleGadget, FontID(10))
State\ImageGadget = ImageGadget(#PB_Any, WindowWidth(State\WindowID) / 2 - 20, 75, 120, 120, 0)
State\DescGadget = TextGadget(#PB_Any, 20, 210, 360, 200, #Empty$)
State\ChkDismiss = CheckBoxGadget(#PB_Any, 20, 342, 200, 25, "Don't show this again")
State\BtnBack = ButtonGadget(#PB_Any, 210, 340, 80, 30, "Back")
State\BtnNext = ButtonGadget(#PB_Any, 300, 340, 80, 30, "Next")
UpdateUI(@State)
Repeat
Select WaitWindowEvent()
Case #PB_Event_CloseWindow
Break
Case #PB_Event_Gadget
Select EventGadget()
Case State\BtnNext
If State\CurrentPage < State\TotalPages - 1
State\CurrentPage + 1
UpdateUI(@State)
Else
State\Result = GetGadgetState(State\ChkDismiss)
If IsFont(10)
FreeFont(10)
EndIf
CloseWindow(State\WindowID)
Break
EndIf
Case State\BtnBack
If State\CurrentPage > 0
State\CurrentPage - 1
UpdateUI(@State)
EndIf
EndSelect
EndSelect
ForEver
ProcedureReturn State\Result
EndProcedure
EndModule
NewList MyTour.Tour::Screen()
; Sample image
Define imgSample = CreateImage(#PB_Any, 120, 120)
StartDrawing(ImageOutput(imgSample))
Box(0,0,120,120, RGB(200, 200, 200))
Circle(60,60,40, RGB(50, 50, 50))
StopDrawing()
AddElement(MyTour())
MyTour()\Title = "Introduction"
MyTour()\Description = "This is step one of your modular tour."
MyTour()\ImageHandle = -1 ; Use -1 for no image
AddElement(MyTour())
MyTour()\Title = "Did You Know?"
MyTour()\Description = "Simply call Tour::Start() and it returns the checkbox result."
MyTour()\ImageHandle = -1
AddElement(MyTour())
MyTour()\Title = "Almost Finished!"
MyTour()\Description = "One more step to go. Check the box below if you want to skip this in the future."
MyTour()\ImageHandle = -1
AddElement(MyTour())
MyTour()\Title = "Ready to Launch!"
MyTour()\Description = "Click 'Finish' to close the tour and start using the application!"
MyTour()\ImageHandle = imgSample
; Capture the user's preference
Define DontShowAgain = Tour::Start(MyTour())
If DontShowAgain
Debug "User wants to skip this in the future. Save this to your config file!"
EndIf