01-26-2026, 09:23 PM
Code: (Select All)
Option _Explicit
' ============================================================
' MiniSheet GUI 10x10 for QB64PE
' Clickable cells, in-place editing, simple formulas:
' =A1 + D5*3
' Supports + - * / and parentheses.
' Text is allowed but treated as 0 in calculations.
' No formatting features (fonts/borders options/etc.).
' ============================================================
Const RMAX% = 10
Const CMAX% = 10
' --- UI layout (pixels) ---
Const WINW% = 980
Const WINH% = 420
Const X0% = 70 ' grid origin x (top-left of cell A1)
Const Y0% = 60 ' grid origin y
Const CELLW% = 85
Const CELLH% = 28
Const HDRH% = 24 ' header height area
Const HDRW% = 50 ' header width area
Const EDITY% = 360 ' editor/status line y
Dim Shared cellIn$(RMAX%, CMAX%)
Dim Shared cellVal!(RMAX%, CMAX%)
Dim Shared state%(RMAX%, CMAX%)
Dim Shared laster$
Dim Shared selR%, selC%
Dim Shared editing%
Dim Shared editText$
Dim Shared prevMouse1%
Dim Shared quit%
Screen _NewImage(WINW%, WINH%, 32)
_Title "MiniSheet GUI (QB64PE) - Click cells, type values/formulas"
InitGrid
MainLoop
End
'init
Sub InitGrid
Dim r%, c%
laster$ = ""
For r% = 1 To RMAX%
For c% = 1 To CMAX%
cellIn$(r%, c%) = ""
cellVal!(r%, c%) = 0!
state%(r%, c%) = 0
Next c%
Next r%
selR% = 1
selC% = 1
editing% = 0
editText$ = ""
prevMouse1% = 0
quit% = 0
End Sub
Sub MainLoop
Do While quit% = 0
_Limit 60
HandleMouse
HandleKeys
DrawUI
Loop
End Sub
Sub HandleMouse
Dim mx%, my%, m1%
Dim r%, c%
Do While _MouseInput
mx% = _MouseX
my% = _MouseY
m1% = _MouseButton(1)
' Detect left-click rising edge
If m1% <> 0 And prevMouse1% = 0 Then
If InGrid%(mx%, my%) Then
MouseToCell mx%, my%, r%, c%
selR% = r%
selC% = c%
' Start editing on click
editing% = -1
editText$ = cellIn$(selR%, selC%)
End If
End If
prevMouse1% = m1%
Loop
End Sub
Function InGrid% (mx%, my%)
Dim gx1%, gy1%, gx2%, gy2%
gx1% = X0%
gy1% = Y0%
gx2% = X0% + CMAX% * CELLW%
gy2% = Y0% + RMAX% * CELLH%
If mx% >= gx1% And mx% < gx2% And my% >= gy1% And my% < gy2% Then
InGrid% = -1
Else
InGrid% = 0
End If
End Function
Sub MouseToCell (mx%, my%, r%, c%)
Dim dx%, dy%
dx% = mx% - X0%
dy% = my% - Y0%
c% = (dx% \ CELLW%) + 1
r% = (dy% \ CELLH%) + 1
If c% < 1 Then c% = 1
If c% > CMAX% Then c% = CMAX%
If r% < 1 Then r% = 1
If r% > RMAX% Then r% = RMAX%
End Sub
'keyboard
Sub HandleKeys
Dim k%
Dim ch$
Dim raw$
k% = _KeyHit
If k% = 0 Then Exit Sub
If editing% <> 0 Then
' Editing mode: build editText$
If k% = 27 Then
' ESC cancels edit
editing% = 0
editText$ = ""
Exit Sub
End If
If k% = 13 Then
' ENTER commits
raw$ = TrimAll$(editText$)
cellIn$(selR%, selC%) = Unquote$(raw$)
editing% = 0
editText$ = ""
Exit Sub
End If
If k% = 8 Then
' BACKSPACE
If Len(editText$) > 0 Then editText$ = Left$(editText$, Len(editText$) - 1)
Exit Sub
End If
' Printable ASCII only (basic)
If k% >= 32 And k% <= 126 Then
ch$ = Chr$(k%)
editText$ = editText$ + ch$
End If
Else
' Not editing: ESC quits
If k% = 27 Then quit% = -1
End If
End Sub
'ui
Sub DrawUI
Cls
DrawHeaders
DrawGrid
DrawEditor
_Display
End Sub
Sub DrawHeaders
Dim c%, r%
Dim x%, y%
Dim s$
' Column letters
For c% = 1 To CMAX%
x% = X0% + (c% - 1) * CELLW% + 6
y% = Y0% - HDRH%
s$ = ColToLetter$(c%)
_PrintString (x%, y%), s$
Next c%
' Row numbers
For r% = 1 To RMAX%
x% = X0% - HDRW%
y% = Y0% + (r% - 1) * CELLH% + 6
s$ = LTrim$(Str$(r%))
_PrintString (x%, y%), s$
Next r%
End Sub
Sub DrawGrid
Dim r%, c%
Dim x1%, y1%, x2%, y2%
Dim raw$, show$
Dim v!
Dim wChars%
laster$ = ""
ClearStates
' Simple grid lines
For c% = 0 To CMAX%
x1% = X0% + c% * CELLW%
y1% = Y0%
x2% = x1%
y2% = Y0% + RMAX% * CELLH%
Line (x1%, y1%)-(x2%, y2%), _RGB32(120, 120, 120)
Next c%
For r% = 0 To RMAX%
x1% = X0%
y1% = Y0% + r% * CELLH%
x2% = X0% + CMAX% * CELLW%
y2% = y1%
Line (x1%, y1%)-(x2%, y2%), _RGB32(120, 120, 120)
Next r%
' Selected cell highlight (just a soft fill so you see where you are)
x1% = X0% + (selC% - 1) * CELLW% + 1
y1% = Y0% + (selR% - 1) * CELLH% + 1
x2% = x1% + CELLW% - 2
y2% = y1% + CELLH% - 2
Line (x1%, y1%)-(x2%, y2%), _RGB32(220, 235, 255), BF
' Cell contents
wChars% = 10 ' rough truncation count for default font
For r% = 1 To RMAX%
For c% = 1 To CMAX%
raw$ = TrimAll$(cellIn$(r%, c%))
show$ = ""
If raw$ <> "" Then
If Left$(raw$, 1) = "=" Then
v! = EvalCell!(r%, c%)
show$ = LTrim$(Str$(v!))
ElseIf IsPlainNumber%(raw$) Then
show$ = raw$
Else
' text
show$ = raw$
End If
End If
If Len(show$) > wChars% Then show$ = Left$(show$, wChars%)
x1% = X0% + (c% - 1) * CELLW% + 4
y1% = Y0% + (r% - 1) * CELLH% + 6
_PrintString (x1%, y1%), show$
Next c%
Next r%
End Sub
Sub DrawEditor
Dim s1$, s2$, s3$
s1$ = "Selected: " + CellName$(selR%, selC%)
s2$ = "Click a cell to edit. Enter=commit, Esc=cancel. Esc (when not editing)=quit."
s3$ = "Input: "
_PrintString (20, EDITY% - 26), s1$
_PrintString (20, EDITY% - 10), s2$
If editing% <> 0 Then
_PrintString (20, EDITY% + 10), s3$ + editText$
Else
_PrintString (20, EDITY% + 10), s3$ + cellIn$(selR%, selC%)
End If
If laster$ <> "" Then
_PrintString (20, EDITY% + 30), "Note: " + laster$
End If
End Sub
Sub ClearStates
Dim r%, c%
For r% = 1 To RMAX%
For c% = 1 To CMAX%
state%(r%, c%) = 0
Next c%
Next r%
End Sub
' Helpers
Function ColToLetter$ (c%)
ColToLetter$ = Chr$(Asc("A") + c% - 1)
End Function
Function CellName$ (r%, c%)
CellName$ = ColToLetter$(c%) + LTrim$(Str$(r%))
End Function
Function TrimAll$ (s$)
TrimAll$ = LTrim$(RTrim$(s$))
End Function
Function Unquote$ (s$)
Dim t$
t$ = TrimAll$(s$)
If Len(t$) >= 2 Then
If Left$(t$, 1) = Chr$(34) And Right$(t$, 1) = Chr$(34) Then
Unquote$ = Mid$(t$, 2, Len(t$) - 2)
Exit Function
End If
End If
Unquote$ = t$
End Function
' Evaluation / Parser
Function EvalCell! (r%, c%)
Dim raw$, s$
Dim idx%, er%
Dim v!
raw$ = TrimAll$(cellIn$(r%, c%))
If state%(r%, c%) = 2 Then
EvalCell! = cellVal!(r%, c%)
Exit Function
End If
If state%(r%, c%) = 1 Then
laster$ = "Cyclic reference detected. Returning 0 for cycle."
EvalCell! = 0!
Exit Function
End If
state%(r%, c%) = 1
If raw$ = "" Then
v! = 0!
ElseIf Left$(raw$, 1) = "=" Then
s$ = Mid$(raw$, 2)
idx% = 1
er% = 0
v! = ParseExpr!(s$, idx%, er%)
SkipSpaces s$, idx%
If er% <> 0 Or idx% <= Len(s$) Then
laster$ = "Formula eror in " + CellName$(r%, c%) + ". Returning 0."
v! = 0!
End If
ElseIf IsPlainNumber%(raw$) Then
idx% = 1
er% = 0
v! = ReadNumber!(raw$, idx%, er%)
If er% <> 0 Then v! = 0!
Else
' text counts as 0 in calculations
v! = 0!
End If
cellVal!(r%, c%) = v!
state%(r%, c%) = 2
EvalCell! = v!
End Function
Function ParseExpr! (s$, idx%, er%)
Dim v!, t!
Dim op$
v! = ParseTerm!(s$, idx%, er%)
If er% <> 0 Then ParseExpr! = 0!: Exit Function
Do
SkipSpaces s$, idx%
If idx% > Len(s$) Then Exit Do
op$ = Mid$(s$, idx%, 1)
If op$ <> "+" And op$ <> "-" Then Exit Do
idx% = idx% + 1
t! = ParseTerm!(s$, idx%, er%)
If er% <> 0 Then ParseExpr! = 0!: Exit Function
If op$ = "+" Then v! = v! + t! Else v! = v! - t!
Loop
ParseExpr! = v!
End Function
Function ParseTerm! (s$, idx%, er%)
Dim v!, f!
Dim op$
v! = ParseFactor!(s$, idx%, er%)
If er% <> 0 Then ParseTerm! = 0!: Exit Function
Do
SkipSpaces s$, idx%
If idx% > Len(s$) Then Exit Do
op$ = Mid$(s$, idx%, 1)
If op$ <> "*" And op$ <> "/" Then Exit Do
idx% = idx% + 1
f! = ParseFactor!(s$, idx%, er%)
If er% <> 0 Then ParseTerm! = 0!: Exit Function
If op$ = "*" Then
v! = v! * f!
Else
If f! = 0! Then
laster$ = "Division by zero. Returning 0."
v! = 0!
Else
v! = v! / f!
End If
End If
Loop
ParseTerm! = v!
End Function
Function ParseFactor! (s$, idx%, er%)
Dim ch$, sign!, v!
Dim cch$, col%, row%
Dim cell$, start%
SkipSpaces s$, idx%
If idx% > Len(s$) Then er% = 1: ParseFactor! = 0!: Exit Function
ch$ = Mid$(s$, idx%, 1)
' Unary +/-
If ch$ = "+" Or ch$ = "-" Then
If ch$ = "-" Then sign! = -1! Else sign! = 1!
idx% = idx% + 1
v! = ParseFactor!(s$, idx%, er%)
ParseFactor! = sign! * v!
Exit Function
End If
' Parentheses
If ch$ = "(" Then
idx% = idx% + 1
v! = ParseExpr!(s$, idx%, er%)
SkipSpaces s$, idx%
If idx% > Len(s$) Or Mid$(s$, idx%, 1) <> ")" Then
er% = 1
ParseFactor! = 0!
Exit Function
End If
idx% = idx% + 1
ParseFactor! = v!
Exit Function
End If
' Cell ref: A1..J10
If IsAlpha%(ch$) Then
start% = idx%
idx% = idx% + 1
Do While idx% <= Len(s$)
cch$ = Mid$(s$, idx%, 1)
If IsDigit%(cch$) = 0 Then Exit Do
idx% = idx% + 1
Loop
cell$ = UCase$(Mid$(s$, start%, idx% - start%))
If CellOK%(cell$, row%, col%) = 0 Then
er% = 1
ParseFactor! = 0!
Exit Function
End If
ParseFactor! = EvalCell!(row%, col%)
Exit Function
End If
' Number
v! = ReadNumber!(s$, idx%, er%)
ParseFactor! = v!
End Function
Sub SkipSpaces (s$, idx%)
Dim ch$
Do While idx% <= Len(s$)
ch$ = Mid$(s$, idx%, 1)
If ch$ <> " " And ch$ <> Chr$(9) Then Exit Do
idx% = idx% + 1
Loop
End Sub
Function ReadNumber! (s$, idx%, er%)
Dim start%, ch$, dotCount%, num$
SkipSpaces s$, idx%
If idx% > Len(s$) Then er% = 1: ReadNumber! = 0!: Exit Function
start% = idx%
dotCount% = 0
Do While idx% <= Len(s$)
ch$ = Mid$(s$, idx%, 1)
If IsDigit%(ch$) Then
idx% = idx% + 1
ElseIf ch$ = "." Then
dotCount% = dotCount% + 1
If dotCount% > 1 Then Exit Do
idx% = idx% + 1
Else
Exit Do
End If
Loop
num$ = Mid$(s$, start%, idx% - start%)
If num$ = "" Or num$ = "." Then
er% = 1
ReadNumber! = 0!
Exit Function
End If
ReadNumber! = CSng(Val(num$))
End Function
Function IsPlainNumber% (s$)
Dim idx%, er%
Dim v!
s$ = TrimAll$(s$)
If s$ = "" Then IsPlainNumber% = 0: Exit Function
idx% = 1
er% = 0
v! = ReadNumber!(s$, idx%, er%)
SkipSpaces s$, idx%
If er% <> 0 Then
IsPlainNumber% = 0
ElseIf idx% <= Len(s$) Then
IsPlainNumber% = 0
Else
IsPlainNumber% = -1
End If
End Function
Function IsAlpha% (ch$)
Dim a%
If ch$ = "" Then IsAlpha% = 0: Exit Function
a% = Asc(UCase$(Left$(ch$, 1)))
If a% >= Asc("A") And a% <= Asc("Z") Then IsAlpha% = -1 Else IsAlpha% = 0
End Function
Function IsDigit% (ch$)
Dim a%
If ch$ = "" Then IsDigit% = 0: Exit Function
a% = Asc(Left$(ch$, 1))
If a% >= Asc("0") And a% <= Asc("9") Then IsDigit% = -1 Else IsDigit% = 0
End Function
Function LetterToCol% (ch$)
Dim a%
ch$ = UCase$(ch$)
a% = Asc(ch$)
If a% < Asc("A") Or a% > Asc("Z") Then LetterToCol% = 0: Exit Function
LetterToCol% = (a% - Asc("A")) + 1
End Function
Function CellOK% (cell$, r%, c%)
Dim ch$, num$, i%, d$
Dim rr%
cell$ = TrimAll$(cell$)
If Len(cell$) < 2 Or Len(cell$) > 3 Then CellOK% = 0: Exit Function
ch$ = Mid$(cell$, 1, 1)
c% = LetterToCol%(ch$)
If c% < 1 Or c% > CMAX% Then CellOK% = 0: Exit Function
num$ = Mid$(cell$, 2)
If num$ = "" Then CellOK% = 0: Exit Function
For i% = 1 To Len(num$)
d$ = Mid$(num$, i%, 1)
If IsDigit%(d$) = 0 Then CellOK% = 0: Exit Function
Next i%
rr% = 0
For i% = 1 To Len(num$)
rr% = rr% * 10 + (Asc(Mid$(num$, i%, 1)) - Asc("0"))
Next i%
If rr% < 1 Or rr% > RMAX% Then CellOK% = 0: Exit Function
r% = rr%
CellOK% = -1
End Function

