Posts: 1,215
Threads: 162
Joined: Apr 2022
Reputation:
34
01-28-2026, 08:05 PM
(This post was last modified: 01-28-2026, 08:05 PM by madscijr.)
If anything QB64 users can learn a lot from both your examples!
I'm not sure how far I'll get with it, but it's a great start. Thank you both!
Posts: 954
Threads: 52
Joined: May 2022
Reputation:
38
Quote:@madscijr - Anyway, it's not broke (yet) but with all the annoying and constant changes Microsoft is determined to force on us (the latest annoyance being the macro recorder now records "Office scripts" by default instead of the standard VBA macros, which although you can disable it, is just another unwanted change and a sign that MS is moving to phase BASIC out of their products (vbscript is already on the chopping block)). Also the cost of Office means you can't share this stuff with someone if they don't have a subscription.
Take a look here; the relationship between VBA for Excel and Office Script is explained very well (have it translated):
Office-Script vs. VBA: Excel – Programmierung für Web und Desktop
Office Script will not replace VBA; it is merely a complement for specific use cases.
Posts: 1,215
Threads: 162
Joined: Apr 2022
Reputation:
34
Well that's good, because I have tons and tons of VBA macros that I use daily with Excel, Word, etc.! (If only they supported macros for OneNote! Microsoft what are you thinking? LoL)
Thanks for sharing that - will check it out later.
PS Isn't it nice we have google to translate this? :-)
Posts: 1,215
Threads: 162
Joined: Apr 2022
Reputation:
34
Implemented some editing - kind of buggy, if you press Esc to cancel edit mode, it sets a flag so that the Esc doesn't also quit out of the program until the keyup event is detected, but something's not right, because then Esc stops being detected after that.
Code: (Select All) ' ################################################################################################################################################################
' QB64PE SPREADSHEET
' There is value in this being a reusable programmable datagrid type control
' you can use in your own QB64 programs.
' MOSTLY BY UNSEEN MACHINE, ORIGINAL CODE AT:
' https://qb64phoenix.com/forum/showthread.php?tid=4417&pid=39358#pid39358
' SOME MODS BY MADSCIJR (STARTED IMPLEMENTING KEYBOARD INPUT)
' Updated with a "todo" list of features needed to make this useful
' (when you think about it, Excel really does a lot!)
' -----------------------------------------------------------------------------
' UNDER CONSTRUCTION: Phase 1-A
' -----------------------------------------------------------------------------
' Editing:
' When user clicks on a cell, remember the column number as temporary first column
' When user presses F2 or double-clicks a cell, enter edit mode:
' - highlight the cell
' - let user type values or a formula in the cell
' - show a blinking cursor as they type
' - if user presses Tab key, save value to cell and move celection to next cell to the right
' - if user presses Enter key, save value to cell and move selection down 1 row, starting at temporary first column
' - if user presses Esc key, exit edit mode - cancel editing and do not save value to cell (revert cell to old value)
' but don't let Esc key inadvertantly quit the program (user must release key before they can press it again to quit)
'
' *CURRENT BUG*
' Currently when you edit then exit when cursor is visible
' the cursor character & sometimes extra characters are saved to the cell.
' TODO: make sure cursor is erased when we exit
' -----------------------------------------------------------------------------
' Phase 1-B
' -----------------------------------------------------------------------------
' Moving around:
' Add horizontal and vertical scroll bars to move around sheet
' for editing sheets larger than the screen.
' Support a large number of rows/columns comparable to Excel
' Clipboard:
' Support cut, copy & paste to/from clipboard
' - support standard Ctrl-x, Ctrl-c, Ctrl-v keyboard shortcuts
' - Copy should copy the cells to clipboard as a standard grid
' (like copying from Excel or Word or an HTML table)
' which can be pasted into Word, OneNote or other rich text editor that supports pasting from Excel or HTML
' - or to Notepad as tab-delimited text
' - Paste should copy from the clipboard to the cells
' (like copying from an HTML or Word table or tab-delimited text into Excel)
' Simple math operations:
' Support simple formulas with basic math operations (add, subtract, multiply, divide)
' See Petr's implementation at https://qb64phoenix.com/forum/showthread.php?tid=4417&pid=39353#pid39353
' String concatenation operations:
' - Concatenate string data, Excel-like cell references like A1 or $A$1.
' Load + Save
' Implement saving/loading a spreadsheet to common formats:
' ODS (OpenOffice and LibreOffice), XLSX, tab-delimited, CSV, XML, JSON
' -----------------------------------------------------------------------------
' TODO Phase 2
' -----------------------------------------------------------------------------
' Support absolute or relative cell references for copying cells with operations
' TYPE IF CELL CONTAINS AND IS COPIED TO THE COPY WOULD BE
' Relative reference B3 =A2 C4 =B3
' Absolute reference B3 =$A$2 C4 =$A$2
' Partially relative B3 =$A2 C4 =$A3
' Partially relative B3 =A$2 C4 =B$2
' Selecting one or more columns or rows with mouse:
' - Clicking a column or row header selects the whole column
' - Click a column or row header and drag to select multiple columns or rows
' - Click a column or row header then hold down Shift + click a 2nd column or row header to select all in between
' DESIGN GOAL:
' Design so that all these features the user can do in the UI,
' can be automated & programmed in the codebehind as easily as possible.
' -----------------------------------------------------------------------------
' TODO Phase 3
' -----------------------------------------------------------------------------
' Cell formatting:
' Support ability to format a cell using Excel's cell formatting syntax for
' - # of decimal places for numbers
' - 1000 separator
' - date format (m, mm, mmm, mmmm, d, dd, ddd, dddd, y, yy, yyyy, h, hh, mm, ss, AM/PM
' Call formulas defined in the QB64PE program:
' - Formulas are QB64PE functions
' - formula name is just the name of the QB64PE function
' - formula can pass in a cell address in notation such a A2
' or absolute notation such as $A2 or A$2 or $A$2
' or a range of cells in notation A2:C4
' - Implement a basic =SUM formula, e.g., =SUM(A2:A10) would add the values
' Add ability to resize column widths
' - by clicking on edge of column and dragging
' - by pressing a hotkey for "column width" inputbox
' -----------------------------------------------------------------------------
' TODO Phase 4 + beyond
' -----------------------------------------------------------------------------
' Multiple sheets?
' Support adding multiple sheets in a document.
' Named ranges
' Support associating a cell address or range of cells with a name
' and referencing it from within another cell or formula.
' Ability to remove or edit a name or the associated address.
' Ability to reference & work with from within a QB64PE function or sub.
' Dropdown controls
' Support defining a dropdown control in a cell (or range) that pulls its values
' from a given range of cells on a given sheet.
' Formula implementation?
' For the formulas we could go a few different ways
' * Use a big CASE statement to redirect to known / supported functions.
' * Support some kind of "eval" function that passes the parameters to the desired function,
' which is a security risk, so only support functions that are safe security-wise
' (basically no networking)
' * Support QB64-script type parser to allow defining functions inside the data
' to save with the sheet. This is non-trivial but Fellippe wrote one already
' that can be repurposed at
' https://github.com/FellippeHeitor/QB64-interpreter
' -----------------------------------------------------------------------------
' HOW TO RUN
' -----------------------------------------------------------------------------
' REQUIRES "QB_Sheets.h" IN SAME FOLDER AS THIS FILE TO COMPILE
' ################################################################################################################################################################
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' CONSTANTS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' KEY CODE INDEX CONSTANTS
Const cKeyNone = 0
Const cKeyEsc = 1
Const cKeyF1 = 2
Const cKeyF2 = 3
Const cKeyF3 = 4
Const cKeyF4 = 5
Const cKeyF5 = 6
Const cKeyF6 = 7
Const cKeyF7 = 8
Const cKeyF8 = 9
Const cKeyF9 = 10
Const cKeyF10 = 11
Const cKeyF11 = 12
Const cKeyF12 = 13
Const cKeyBackTick = 14
Const cKey1 = 15
Const cKey2 = 16
Const cKey3 = 17
Const cKey4 = 18
Const cKey5 = 19
Const cKey6 = 20
Const cKey7 = 21
Const cKey8 = 22
Const cKey9 = 23
Const cKey0 = 24
Const cKeyMinus = 25
Const cKeyEqual = 26
Const cKeyBackspace = 27
Const cKeyTilde = 28
Const cKeyExclamation = 29
Const cKeyAt = 30
Const cKeyPound = 31
Const cKeyDollar = 32
Const cKeyPercent = 33
Const cKeyCaret = 34
Const cKeyAmpersand = 35
Const cKeyAsterisk = 36
Const cKeyParenOpen = 37
Const cKeyParenClose = 38
Const cKeyUnderscore = 39
Const cKeyPlus = 40
Const cKeyInsert = 41
Const cKeyHome = 42
Const cKeyPageUp = 43
Const cKeyDelete = 44
Const cKeyEnd = 45
Const cKeyPageDown = 46
Const cKeyTab = 47
Const cKeyCapsLock = 48
Const cKeyPrintScreen = 49
Const cKeyScrollLock = 50
Const cKeyPauseBreak = 51
Const cKeyEnter = 52
Const cKeySquareOpen = 53
Const cKeySquareClose = 54
Const cKeyBackSlash = 55
Const cKeyCurlyOpen = 56
Const cKeyCurlyClose = 57
Const cKeyPipe = 58
Const cKeyComma = 59
Const cKeyPeriod = 60
Const cKeySlash = 61
Const cKeyLt = 62
Const cKeyGt = 63
Const cKeyQuestion = 64
Const cKeySemicolon = 65
Const cKeyApostrophe = 66
Const cKeyColon = 67
Const cKeyQuote = 68
Const cKeyShiftLeft = 69
Const cKeyShiftRight = 70
Const cKeyCtrlLeft = 71
Const cKeyCtrlRight = 72
Const cKeyAltLeft = 73
Const cKeyAltRight = 74
Const cKeyWinLeft = 75
Const cKeyWinRight = 76
Const cKeyMenu = 77
Const cKeySpace = 78
Const cKeyLeftArrow = 79
Const cKeyUpArrow = 80
Const cKeyDownArrow = 81
Const cKeyRightArrow = 82
Const cKeyNumLock = 83
Const cKeyA = 84
Const cKeyB = 85
Const cKeyC = 86
Const cKeyD = 87
Const cKeyE = 88
Const cKeyF = 89
Const cKeyG = 90
Const cKeyH = 91
Const cKeyI = 92
Const cKeyJ = 93
Const cKeyK = 94
Const cKeyL = 95
Const cKeyM = 96
Const cKeyN = 97
Const cKeyO = 98
Const cKeyP = 99
Const cKeyQ = 100
Const cKeyR = 101
Const cKeyS = 102
Const cKeyT = 103
Const cKeyU = 104
Const cKeyV = 105
Const cKeyW = 106
Const cKeyX = 107
Const cKeyY = 108
Const cKeyZ = 109
Const cKeyUpperA = 110
Const cKeyUpperB = 111
Const cKeyUpperC = 112
Const cKeyUpperD = 113
Const cKeyUpperE = 114
Const cKeyUpperF = 115
Const cKeyUpperG = 116
Const cKeyUpperH = 117
Const cKeyUpperI = 118
Const cKeyUpperJ = 119
Const cKeyUpperK = 120
Const cKeyUpperL = 121
Const cKeyUpperM = 122
Const cKeyUpperN = 123
Const cKeyUpperO = 124
Const cKeyUpperP = 125
Const cKeyUpperQ = 126
Const cKeyUpperR = 127
Const cKeyUpperS = 128
Const cKeyUpperT = 129
Const cKeyUpperU = 130
Const cKeyUpperV = 131
Const cKeyUpperW = 132
Const cKeyUpperX = 133
Const cKeyUpperY = 134
Const cKeyUpperZ = 135
Const cKeypadSlash = 136
Const cKeypadMultiply = 137
Const cKeypadMinus = 138
Const cKeypad7Home = 139
Const cKeypad8Up = 140
Const cKeypad9PgUp = 141
Const cKeypadPlus = 142
Const cKeypad4Left = 143
Const cKeypad5 = 144
Const cKeypad6Right = 145
Const cKeypad1End = 146
Const cKeypad2Down = 147
Const cKeypad3PgDn = 148
Const cKeypadEnter = 149
Const cKeypad0Ins = 150
Const cKeypadPeriodDel = 151
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' TYPES
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Type MouseState
X As Long: Y As Long: B1 As _Byte: Wheel As Long
End Type
' Single-Cell Messenger UDT
' This is used to "fetch" and "commit" all properties of one cell at once.
Type CellProperties
Value As String: IntValue As _Integer64: DblValue As Double
BG As _Unsigned Long: FG As _Unsigned Long: Locked As _Byte: VarType As _Byte
End Type
Type GridView
Handle As _Offset
TopRow As Long
LeftCol As Long
SelR1 As Long
SelC1 As Long
SelR2 As Long
SelC2 As Long
IsDragging As _Byte
' Phase 1 Additions to track the editing state and the cursor position:
IsEditing As _Byte
EditBuffer As String
CursorPos As Integer
TempFirstCol As Long
IsCancellingEdit As _Byte
End Type ' GridView
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' LIBRARY
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Declare Library "QB_Sheets"
' Lifecycle Management
Function Sheet_New%& Alias "QBS_New" (ByVal r As Long, ByVal c As Long)
Sub Sheet_Free Alias "QBS_Free" (ByVal h As _Offset)
' Persistence (Binary Save/Load)
Function Sheet_Save& Alias "QBS_Save" (ByVal h As _Offset, filename As String)
Function Sheet_Load%& Alias "QBS_Load" (filename As String)
' Data Setters (Individual)
Sub Sheet_SetSTR Alias "QBS_SetStr" (ByVal h As _Offset, ByVal r As Long, ByVal c As Long, v As String)
Sub Sheet_SetINT Alias "QBS_SetInt" (ByVal h As _Offset, ByVal r As Long, ByVal c As Long, ByVal v As _Integer64)
Sub Sheet_SetDBL Alias "QBS_SetDbl" (ByVal h As _Offset, ByVal r As Long, ByVal c As Long, ByVal v As Double)
' Data Getters (Individual)
Function Sheet_GetSTR$ Alias "QBS_GetStr" (ByVal h As _Offset, ByVal r As Long, ByVal c As Long)
Function Sheet_GetINT& Alias "QBS_GetInt" (ByVal h As _Offset, ByVal r As Long, ByVal c As Long)
Function Sheet_GetDBL# Alias "QBS_GetDbl" (ByVal h As _Offset, ByVal r As Long, ByVal c As Long)
' Metadata Fetching
' Note: Pass _OFFSET(CellPropertiesVariable.BG) to fill the UDT instantly from C++
Sub Sheet_GetInfo Alias "QBS_GetInfo" (ByVal h As _Offset, ByVal r As Long, ByVal c As Long, ByVal infoPtr As _Offset)
' Formatting and Physical Layout
Sub Sheet_Format Alias "QBS_Format" (ByVal h As _Offset, ByVal r As Long, ByVal c As Long, ByVal bg As _Unsigned Long, ByVal fg As _Unsigned Long, ByVal lock As Long)
Sub Sheet_Size Alias "QBS_Size" (ByVal h As _Offset, ByVal idx As Long, ByVal size As Long, ByVal isRow As Long)
Function Sheet_GetSize% Alias "QBS_GetSize" (ByVal h As _Offset, ByVal idx As Long, ByVal isRow As Long)
End Declare
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' GLOBALS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dim Shared Mouse As MouseState, OldMouse As MouseState
Dim Shared MainGrid As GridView
Dim Shared arrKeyHitDown(1 To 151) As Integer ' _KEYHIT key down event codes
Dim Shared arrKeyHitUp(1 To 151) As Integer ' _KEYHIT key up event codes
Dim Shared arrButton(1 To 151) As Integer ' _BUTTON key codes
Dim Shared arrKeyState(1 To 151) As Integer ' tracks keydown and keyup for _BUTTON
Dim Shared ClickedColumn As Long: ClickedColumn = 0 ' remember column user clicks on, when they hit Enter, move down 1 row to this column
Dim Shared IsRunning As Integer
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' QB64 Spreadsheet Core
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' Initialize
'$Dynamic
Screen _NewImage(1024, 768, 32)
_Title "QB_Sheets Core Engine"
InitKeyCodes
MainGrid.Handle = Sheet_New(10000, 100)
MainGrid.IsEditing = _FALSE
MainGrid.EditBuffer = ""
MainGrid.CursorPos = 0
MainGrid.TempFirstCol = 0
MainGrid.IsCancellingEdit = _FALSE
' Populate some test data
For i = 0 To 50: Sheet_SetSTR MainGrid.Handle, i, 0, "Item" + Str$(i): Next i
IsRunning = _TRUE
' ================================================================================================================================================================
' MAIN LOOP
' ================================================================================================================================================================
Do
_Limit 60
HandleGridInput MainGrid
Cls '_RGB32(50, 50, 50)
DrawGridWithHeaders MainGrid, 0, 0, _Width, _Height
If arrKeyState(cKeyEsc) = _FALSE Then
End If
_Display
Loop Until IsRunning = _FALSE
Sheet_Free MainGrid.Handle
System
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' SUBS
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' /////////////////////////////////////////////////////////////////////////////
Sub HandleGridInput (G As GridView)
' --- Header Constants (Must match your DrawGridWithHeaders) ---
Dim hdrW As Integer: hdrW = 40 ' Width of Row labels
Dim hdrH As Integer: hdrH = 25 ' Height of Col labels
Dim r As Long, c As Long
' Update mouse input
OldMouse = Mouse
Do While _MouseInput
Mouse.X = _MouseX: Mouse.Y = _MouseY: Mouse.B1 = _MouseButton(1)
Mouse.Wheel = Mouse.Wheel + _MouseWheel
Loop
' Check if mouse is actually inside the data area (not on headers)
If Mouse.X >= hdrW And Mouse.Y >= hdrH Then
' Adjust mouse coordinates to Grid-Space
' We subtract the header offsets so GetCellAtMouse sees the "0,0" of the data
GetCellAtMouse G, Mouse.X - hdrW, Mouse.Y - hdrH, r, c
' Start Select
If Mouse.B1 And Not OldMouse.B1 Then
' BEGIN Remember the TempFirstCol when a user selects a cell.
' Save current buffer if switching cells while editing
If G.IsEditing Then CommitEdit G
G.SelR1 = r: G.SelC1 = c
G.SelR2 = r: G.SelC2 = c
G.TempFirstCol = c ' Remember the column for Enter key logic [cite: 183]
G.IsDragging = -1
' TODO: Double-click to enter edit mode
' (Basic implementation: check if same cell clicked rapidly)
' Add double-click timer logic here if needed
End If
' Drag Select
If Mouse.B1 And G.IsDragging Then
G.SelR2 = r: G.SelC2 = c
End If
ElseIf Mouse.B1 And Not OldMouse.B1 Then
' User clicked in the header area
' TIP: You could add logic here to select an entire Row or Column
End If
' End Drag (Always reset regardless of where the mouse is)
If Not Mouse.B1 Then G.IsDragging = 0
' Scroll (Mouse wheel works anywhere on the window)
If Mouse.Wheel <> OldMouse.Wheel Then
G.TopRow = G.TopRow - (Mouse.Wheel - OldMouse.Wheel)
If G.TopRow < 0 Then G.TopRow = 0
' Reset wheel delta so it doesn't accumulate
Mouse.Wheel = 0: OldMouse.Wheel = 0
End If
' Keyboard input
HandleKeyboard G
End Sub ' HandleGridInput
' /////////////////////////////////////////////////////////////////////////////
Sub DrawGrid (G As GridView, x1, y1, x2, y2)
' --- Move all DIMS to start ---
Dim curY As Long, curX As Long
Dim r As Long, c As Long
Dim rowH As Integer, colW As Integer
Dim Prop As CellProperties
Dim dispText$
curY = y1
r = G.TopRow
Do While curY < y2 And r < 10000
rowH = Sheet_GetSize(G.Handle, r, 1)
curX = x1
c = G.LeftCol
Do While curX < x2 And c < 100
colW = Sheet_GetSize(G.Handle, c, 0)
' Fetch metadata (BG, FG, Lock, VarType)
Sheet_GetInfo G.Handle, r, c, _Offset(Prop.BG)
' Draw Cell Background and Border
Line (curX, curY)-(curX + colW - 1, curY + rowH - 1), Prop.BG, BF
Line (curX, curY)-(curX + colW - 1, curY + rowH - 1), _RGB32(200, 200, 200), B
' Selection Overlay
If IsInRange(r, c, G.SelR1, G.SelC1, G.SelR2, G.SelC2) Then
Line (curX, curY)-(curX + colW - 1, curY + rowH - 1), _RGB32(0, 120, 215, 80), BF
End If
Color Prop.FG, Prop.BG
' Draw text inside cell
If G.IsEditing And r = G.SelR1 And c = G.SelC1 Then
' Provide visual feedback if editing
' Highlight editing cell
Line (curX, curY)-(curX + colW - 1, curY + rowH - 1), _RGB32(255, 255, 255), BF
Color _RGB32(0, 0, 0)
' Show a blinking cursor
' TODO: make sure cursor is erased when we exit
' TODO: currently when you edit then exit when cursor is visible
' TODO: the cursor character & sometimes extra characters are saved to the cell
dispText$ = G.EditBuffer
If (Timer * 2) Mod 2 = 0 Then dispText$ = dispText$ + "|"
_PrintString (curX + 4, curY + (rowH / 2 - 8)), dispText$
Else
' Draw Text Content
If Prop.VarType > 0 Then
_PrintString (curX + 4, curY + (rowH / 2 - 8)), Sheet_GetSTR$(G.Handle, r, c)
End If
End If
' Goto next column
curX = curX + colW
c = c + 1
Loop
' Goto next row
curY = curY + rowH
r = r + 1
Loop
End Sub ' DrawGrid
' /////////////////////////////////////////////////////////////////////////////
Sub GetCellAtMouse (G As GridView, mx, my, outR As Long, outC As Long)
' --- Move all DIMS to start ---
Dim curX As Long, curY As Long
Dim w As Integer, h As Integer
' Find Column
curX = 0 ' Assuming grid starts at 0, adjust if x1 > 0
outC = G.LeftCol
Do
w = Sheet_GetSize(G.Handle, outC, 0)
If mx >= curX And mx < curX + w Then Exit Do
curX = curX + w
outC = outC + 1
' Safety break to prevent infinite loops on 0-width or off-screen
If outC > 16384 Or curX > _Width Then Exit Do
Loop
' Find Row
curY = 0
outR = G.TopRow
Do
h = Sheet_GetSize(G.Handle, outR, 1)
If my >= curY And my < curY + h Then Exit Do
curY = curY + h
outR = outR + 1
If outR > 1000000 Or curY > _Height Then Exit Do
Loop
End Sub ' GetCellAtMouse
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' BEGIN Implement Editing Subs
' New subroutines to manage the edit lifecycle
' (F2 to enter, typing, Enter/Tab to save, Esc to cancel).
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' /////////////////////////////////////////////////////////////////////////////
Sub TriggerEditMode (G As GridView, bClearCell As Integer)
G.IsEditing = -1
If bClearCell = _FALSE Then
G.EditBuffer = Sheet_GetSTR$(G.Handle, G.SelR1, G.SelC1)
Else
G.EditBuffer = ""
End If
G.CursorPos = Len(G.EditBuffer) + 1
End Sub ' TriggerEditMode
' /////////////////////////////////////////////////////////////////////////////
Sub CommitEdit (G As GridView)
Sheet_SetSTR G.Handle, G.SelR1, G.SelC1, G.EditBuffer
G.IsEditing = 0
G.EditBuffer = ""
End Sub ' CommitEdit
' /////////////////////////////////////////////////////////////////////////////
Sub CancelEdit (G As GridView)
G.IsEditing = 0
G.EditBuffer = ""
G.IsCancellingEdit = _TRUE
End Sub ' CancelEdit
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' END Implement Editing Subs
' ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
' /////////////////////////////////////////////////////////////////////////////
Function IsInRange (r, c, r1, c1, r2, c2)
Dim minR, maxR, minC, maxC
If r1 < r2 Then minR = r1: maxR = r2 Else minR = r2: maxR = r1
If c1 < c2 Then minC = c1: maxC = c2 Else minC = c2: maxC = c1
If r >= minR And r <= maxR And c >= minC And c <= maxC Then IsInRange = -1
End Function ' IsInRange
' /////////////////////////////////////////////////////////////////////////////
Function GetColName$ (c As Long)
Dim num As Long: num = c + 1 ' Convert 0-based index to 1-based
Dim colName As String
Dim remainder As Integer
Do While num > 0
remainder = (num - 1) Mod 26
colName = Chr$(65 + remainder) + colName
num = (num - remainder) \ 26
Loop
GetColName$ = colName
End Function ' GetColName$
' /////////////////////////////////////////////////////////////////////////////
Sub DrawGridWithHeaders (G As GridView, x1, y1, x2, y2)
Dim curY As Long, curX As Long
Dim r As Long, c As Long
Dim rowH As Integer, colW As Integer
Dim Prop As CellProperties
Dim hdrW As Integer: hdrW = 40 ' Row labels width
Dim hdrH As Integer: hdrH = 25 ' Column labels height
Color _RGB32(0, 0, 0), _RGBA32(0, 0, 0, 0)
' 1. Draw Corner Block (Intersection of headers)
Line (x1, y1)-(x1 + hdrW - 1, y1 + hdrH - 1), _RGB32(220, 220, 220), BF
Line (x1, y1)-(x1 + hdrW - 1, y1 + hdrH - 1), _RGB32(100, 100, 100), B
' 2. Draw Column Headers (A, B, C...)
curX = x1 + hdrW: c = G.LeftCol
Do While curX < x2
colW = Sheet_GetSize(G.Handle, c, 0)
Line (curX, y1)-(curX + colW - 1, y1 + hdrH - 1), _RGB32(220, 220, 220), BF
Line (curX, y1)-(curX + colW - 1, y1 + hdrH - 1), _RGB32(100, 100, 100), B
_PrintString (curX + (colW \ 2 - 4), y1 + 5), GetColName$(c)
curX = curX + colW: c = c + 1
Loop
' 3. Draw Row Headers (1, 2, 3...)
curY = y1 + hdrH: r = G.TopRow
Do While curY < y2
rowH = Sheet_GetSize(G.Handle, r, 1)
Line (x1, curY)-(x1 + hdrW - 1, curY + rowH - 1), _RGB32(220, 220, 220), BF
Line (x1, curY)-(x1 + hdrW - 1, curY + rowH - 1), _RGB32(100, 100, 100), B
_PrintString (x1 + 5, curY + 5), LTrim$(Str$(r + 1))
curY = curY + rowH: r = r + 1
Loop
' 4. Draw Main Grid Data (Shifted by hdrW and hdrH)
DrawGrid G, x1 + hdrW, y1 + hdrH, x2, y2
End Sub ' DrawGridWithHeaders
' /////////////////////////////////////////////////////////////////////////////
Sub HandleKeyboard (G As GridView)
Dim kh%
Dim k$
' UPDATE KEYBOARD INPUT
While _DeviceInput(1): Wend ' clear and update the keyboard buffer
kh% = _KeyHit
' -----------------------------------------------------------------------------
' Process text input
' -----------------------------------------------------------------------------
' Handle Edit Mode Input
' TODO: support cursor + Home + End keys to move left/right/etc. while editing
If G.IsEditing Then
Select Case kh%
Case arrKeyHitDown(cKeyEsc) ' Esc: Revert and exit
' TODO: fix Esc key being disabled when we Esc out of edit mode so user can use Esc to quit
'arrKeyState(cKeyEsc) = _TRUE
CancelEdit G
Case arrKeyHitDown(cKeyEnter) ' Enter: Save and move down [cite: 183]
arrKeyState(cKeyEnter) = _TRUE
CommitEdit G
'TODO: make sure cursor is erased when we exit & no unwanted text saved to cell
G.SelR1 = G.SelR1 + 1: G.SelC1 = G.TempFirstCol
G.SelR2 = G.SelR1: G.SelC2 = G.SelC1
Case arrKeyHitDown(cKeyTab) ' Tab: Save and move right
arrKeyState(cKeyTab) = _TRUE
CommitEdit G
'TODO: make sure cursor is erased when we exit & no unwanted text saved to cell
G.SelC1 = G.SelC1 + 1: G.SelC2 = G.SelC1
Case arrKeyHitDown(cKeyBackspace) ' Backspace
arrKeyState(cKeyBackspace) = _TRUE
If Len(G.EditBuffer) > 0 Then
G.EditBuffer = Left$(G.EditBuffer, Len(G.EditBuffer) - 1)
End If
Case Else
k$ = InKey$
' TODO: IGNORE KEY CODES WE DON'T WANT
If Len(k$) = 1 Then
If Asc(k$) >= 32 Then
G.EditBuffer = G.EditBuffer + k$ ' Type values/formulas
End If
End If
End Select
' Skip navigation keys while editing
GoTo ClearKeyboardBuffer
End If
' -----------------------------------------------------------------------------
' DETECT KEYS WITH _KEYHIT
' -----------------------------------------------------------------------------
' ARROW KEYS MOVE UP
If kh% = arrKeyHitDown(cKeyUpArrow) Then
If arrKeyState(cKeyUpArrow) = _FALSE Then
arrKeyState(cKeyUpArrow) = _TRUE
G.SelR1 = G.SelR1 - 1: G.SelR2 = G.SelR1
GoTo ClearKeyboardBuffer
End If
ElseIf kh% = arrKeyHitUp(cKeyUpArrow) Then
arrKeyState(cKeyUpArrow) = _FALSE
GoTo ClearKeyboardBuffer
End If
' ARROW KEYS MOVE DOWN
If kh% = arrKeyHitDown(cKeyDownArrow) Then
If arrKeyState(cKeyDownArrow) = _FALSE Then
arrKeyState(cKeyDownArrow) = _TRUE
G.SelR1 = G.SelR1 + 1: G.SelR2 = G.SelR1
GoTo ClearKeyboardBuffer
End If
ElseIf kh% = arrKeyHitUp(cKeyDownArrow) Then
arrKeyState(cKeyDownArrow) = _FALSE
GoTo ClearKeyboardBuffer
End If
' ARROW KEYS MOVE LEFT
If kh% = arrKeyHitDown(cKeyLeftArrow) Then
If arrKeyState(cKeyLeftArrow) = _FALSE Then
arrKeyState(cKeyLeftArrow) = _TRUE
G.SelC1 = G.SelC1 - 1: G.SelC2 = G.SelC1
GoTo ClearKeyboardBuffer
End If
ElseIf kh% = arrKeyHitUp(cKeyLeftArrow) Then
arrKeyState(cKeyLeftArrow) = _FALSE
GoTo ClearKeyboardBuffer
End If
' ARROW KEYS MOVE RIGHT
If kh% = arrKeyHitDown(cKeyRightArrow) Then
If arrKeyState(cKeyRightArrow) = _FALSE Then
arrKeyState(cKeyRightArrow) = _TRUE
G.SelC1 = G.SelC1 + 1: G.SelC2 = G.SelC1
GoTo ClearKeyboardBuffer
End If
ElseIf kh% = arrKeyHitUp(cKeyRightArrow) Then
arrKeyState(cKeyRightArrow) = _FALSE
GoTo ClearKeyboardBuffer
End If
' TAB MOVES ONE CELL OVER
If kh% = arrKeyHitDown(cKeyTab) Then
If arrKeyState(cKeyTab) = _FALSE Then
arrKeyState(cKeyTab) = _TRUE
G.SelC1 = G.SelC1 + 1: G.SelC2 = G.SelC1
GoTo ClearKeyboardBuffer
End If
ElseIf kh% = arrKeyHitUp(cKeyTab) Then
arrKeyState(cKeyTab) = _FALSE
GoTo ClearKeyboardBuffer
End If
' ENTER SHOULD END DATA ENTRY MODE AND MOVE TO NEXT LINE
If kh% = arrKeyHitDown(cKeyEnter) Then
If arrKeyState(cKeyEnter) = _FALSE Then
arrKeyState(cKeyEnter) = _TRUE
'CloseEditMode(G)
'Sheet_SetSTR MainGrid.Handle, G.SelR1, G.SelC1, "Enter"
G.SelR1 = G.SelR1 + 1: G.SelR2 = G.SelR1
GoTo ClearKeyboardBuffer
End If
ElseIf kh% = arrKeyHitUp(cKeyEnter) Then
arrKeyState(cKeyEnter) = _FALSE
GoTo ClearKeyboardBuffer
End If
' F2 ENTERS EDIT MODE
If kh% = arrKeyHitDown(cKeyF2) Then
If arrKeyState(cKeyF2) = _FALSE Then
arrKeyState(cKeyF2) = _TRUE
TriggerEditMode G, _FALSE
'Sheet_SetSTR MainGrid.Handle, G.SelR1, G.SelC1, "F2=edit"
GoTo ClearKeyboardBuffer
End If
ElseIf kh% = arrKeyHitUp(cKeyF2) Then
arrKeyState(cKeyF2) = _FALSE
GoTo ClearKeyboardBuffer
End If
' BACKSPACE CLEARS CELL AND ENTERS EDIT MODE
If kh% = arrKeyHitDown(cKeyBackspace) Then
If arrKeyState(cKeyBackspace) = _FALSE Then
arrKeyState(cKeyBackspace) = _TRUE
TriggerEditMode G, _TRUE
'Sheet_SetSTR MainGrid.Handle, G.SelR1, G.SelC1, "F2=edit"
GoTo ClearKeyboardBuffer
End If
ElseIf kh% = arrKeyHitUp(cKeyBackspace) Then
arrKeyState(cKeyBackspace) = _FALSE
GoTo ClearKeyboardBuffer
End If
' ESC = QUIT PROGRAM
If kh% = arrKeyHitDown(cKeyEsc) Then
If G.IsCancellingEdit = _FALSE Then
If arrKeyState(cKeyEsc) = _FALSE Then
arrKeyState(cKeyEsc) = _TRUE
IsRunning = _FALSE
GoTo ClearKeyboardBuffer
End If
End If
ElseIf kh% = arrKeyHitUp(cKeyEsc) Then
G.IsCancellingEdit = _FALSE
arrKeyState(cKeyEsc) = _FALSE
GoTo ClearKeyboardBuffer
End If
' -----------------------------------------------------------------------------
' DETECT KEYS WITH _BUTTON
' -----------------------------------------------------------------------------
If _TRUE = _FALSE Then
' ARROW KEYS MOVE
If _Button(arrButton(cKeyUpArrow)) Then
If arrKeyState(cKeyUpArrow) = _FALSE Then
arrKeyState(cKeyUpArrow) = _TRUE
G.SelR1 = G.SelR1 - 1: G.SelR2 = G.SelR1
GoTo ClearKeyboardBuffer
End If
Else
arrKeyState(cKeyUpArrow) = _FALSE
End If
' ARROW KEYS MOVE DOWN
If _Button(arrButton(cKeyDownArrow)) Then
If arrKeyState(cKeyDownArrow) = _FALSE Then
arrKeyState(cKeyDownArrow) = _TRUE
G.SelR1 = G.SelR1 + 1: G.SelR2 = G.SelR1
GoTo ClearKeyboardBuffer
End If
Else
arrKeyState(cKeyDownArrow) = _FALSE
End If
' ARROW KEYS MOVE LEFT
If _Button(arrButton(cKeyLeftArrow)) Then
If arrKeyState(cKeyLeftArrow) = _FALSE Then
arrKeyState(cKeyLeftArrow) = _TRUE
G.SelC1 = G.SelC1 - 1: G.SelC2 = G.SelC1
GoTo ClearKeyboardBuffer
End If
Else
arrKeyState(cKeyLeftArrow) = _FALSE
End If
' ARROW KEYS MOVE RIGHT
If _Button(arrButton(cKeyRightArrow)) Then
If arrKeyState(cKeyRightArrow) = _FALSE Then
arrKeyState(cKeyRightArrow) = _TRUE
G.SelC1 = G.SelC1 + 1: G.SelC2 = G.SelC1
GoTo ClearKeyboardBuffer
End If
Else
arrKeyState(cKeyRightArrow) = _FALSE
End If
' ENTER SHOULD END DATA ENTRY MODE AND MOVE TO NEXT LINE
If _Button(arrButton(cKeyEnter)) Then
If arrKeyState(cKeyEnter) = _FALSE Then
arrKeyState(cKeyEnter) = _TRUE
'CloseEditMode(G)
'Sheet_SetSTR MainGrid.Handle, G.SelR1, G.SelC1, "Enter"
G.SelR1 = G.SelR1 + 1: G.SelR2 = G.SelR1
GoTo ClearKeyboardBuffer
End If
ElseIf _KeyHit = arrKeyHitUp(cKeyEnter) Then
arrKeyState(cKeyEnter) = _FALSE
End If
' F2 ENTERS EDIT MODE
If _Button(arrButton(cKeyF2)) Then
If arrKeyState(cKeyF2) = _FALSE Then
arrKeyState(cKeyF2) = _TRUE
TriggerEditMode G, _FALSE
'Sheet_SetSTR MainGrid.Handle, G.SelR1, G.SelC1, "F2=edit"
GoTo ClearKeyboardBuffer
End If
ElseIf _KeyHit = arrKeyHitUp(cKeyF2) Then
arrKeyState(cKeyF2) = _FALSE
End If
End If
'' -----------------------------------------------------------------------------
'' DETECT KEYS WITH InKey$
'' -----------------------------------------------------------------------------
'Dim k$: k$ = InKey$
'If k$ = "" Then Exit Sub
'Select Case k$
' Case Chr$(0) + "H": ' Up Arrow
' G.SelR1 = G.SelR1 - 1: G.SelR2 = G.SelR1
' Case Chr$(0) + "P": ' Down Arrow
' G.SelR1 = G.SelR1 + 1: G.SelR2 = G.SelR1
' Case Chr$(0) + "K": ' Left Arrow
' G.SelC1 = G.SelC1 - 1: G.SelC2 = G.SelC1
' Case Chr$(0) + "M": ' Right Arrow
' G.SelC1 = G.SelC1 + 1: G.SelC2 = G.SelC1
' Case Chr$(13): ' Enter Key - Start Editing
' 'TriggerEditMode G, _FALSE
' Case Chr$(0) + Chr$(60): ' F2 key = start editing
' 'TriggerEditMode G, _ FALSE
' 'Sheet_SetSTR MainGrid.Handle, G.SelR1, G.SelC1, "F2=edit"
'End Select
' -----------------------------------------------------------------------------
' RESUME AFTER KEY DETECTION
' -----------------------------------------------------------------------------
ClearKeyboardBuffer:
_KeyClear ' CLEAR KEYBOARD BUFFER
'_Delay .25
' Keep selection within bounds
If G.SelR1 < 0 Then G.SelR1 = 0: G.SelR2 = 0
If G.SelC1 < 0 Then G.SelC1 = 0: G.SelC2 = 0
' Auto-Scroll Viewport if selection goes off-screen
If G.SelR1 < G.TopRow Then G.TopRow = G.SelR1
' TODO: (Repeat similar logic for Bottom/Right bounds)
End Sub ' HandleKeyboard
' /////////////////////////////////////////////////////////////////////////////
Sub ExportToJSON (G As GridView, FileName As String)
Dim Q As String: Q = Chr$(34) ' Store the quote character
Open FileName For Output As #1
Print #1, "{"
Print #1, " " + Q + "rows" + Q + ": ["
For r = 0 To TotalRows - 1
Print #1, " ["
For c = 0 To TotalCols - 1
txt$ = Sheet_GetSTR$(G.Handle, r, c)
' Wraps content in quotes: "Value"
Print #1, " " + Q + txt$ + Q;
If c < TotalCols - 1 Then Print #1, "," Else Print #1, ""
Next c
Print #1, " ]";
If r < TotalRows - 1 Then Print #1, "," Else Print #1, ""
Next r
Print #1, " ]"
Print #1, "}"
Close #1
End Sub ' ExportToJSON
' /////////////////////////////////////////////////////////////////////////////
Sub ExportToXML (G As GridView, FileName As String)
Dim Q As String: Q = Chr$(34)
Open FileName For Output As #1
Print #1, "<?xml version=" + Q + "1.0" + Q + " encoding=" + Q + "UTF-8" + Q + "?>"
Print #1, "<Workbook>"
For r = 0 To TotalRows - 1
' Example: <Row id="0">
Print #1, " <Row id=" + Q + LTrim$(Str$(r)) + Q + ">"
For c = 0 To TotalCols - 1
txt$ = Sheet_GetSTR$(G.Handle, r, c)
Print #1, " <Cell col=" + Q + LTrim$(Str$(c)) + Q + ">" + txt$ + "</Cell>"
Next c
Print #1, " </Row>"
Next r
Print #1, "</Workbook>"
Close #1
End Sub ' ExportToXML
' /////////////////////////////////////////////////////////////////////////////
Sub InitKeyCodes
' Keydown codes for _KeyHit (value of 0 means undetectable or ambiguous, use _BUTTON or other method)
arrKeyHitDown(cKeyEsc) = 27
arrKeyHitDown(cKeyF1) = 15104
arrKeyHitDown(cKeyF2) = 15360
arrKeyHitDown(cKeyF3) = 15616
arrKeyHitDown(cKeyF4) = 15872
arrKeyHitDown(cKeyF5) = 16128
arrKeyHitDown(cKeyF6) = 16384
arrKeyHitDown(cKeyF7) = 16640
arrKeyHitDown(cKeyF8) = 16896
arrKeyHitDown(cKeyF9) = 17152
arrKeyHitDown(cKeyF10) = 17408
arrKeyHitDown(cKeyF11) = -31488
arrKeyHitDown(cKeyF12) = -31232
arrKeyHitDown(cKeyBackTick) = 96
arrKeyHitDown(cKey1) = 49
arrKeyHitDown(cKey2) = 50
arrKeyHitDown(cKey3) = 51
arrKeyHitDown(cKey4) = 52
arrKeyHitDown(cKey5) = 53
arrKeyHitDown(cKey6) = 54
arrKeyHitDown(cKey7) = 55
arrKeyHitDown(cKey8) = 56
arrKeyHitDown(cKey9) = 57
arrKeyHitDown(cKey0) = 48
arrKeyHitDown(cKeyMinus) = 45
arrKeyHitDown(cKeyEqual) = 61
arrKeyHitDown(cKeyBackspace) = 8
arrKeyHitDown(cKeyTilde) = 126
arrKeyHitDown(cKeyExclamation) = 33
arrKeyHitDown(cKeyAt) = 64
arrKeyHitDown(cKeyPound) = 35
arrKeyHitDown(cKeyDollar) = 36
arrKeyHitDown(cKeyPercent) = 37
arrKeyHitDown(cKeyCaret) = 94
arrKeyHitDown(cKeyAmpersand) = 38
arrKeyHitDown(cKeyAsterisk) = 42
arrKeyHitDown(cKeyParenOpen) = 40
arrKeyHitDown(cKeyParenClose) = 41
arrKeyHitDown(cKeyUnderscore) = 95
arrKeyHitDown(cKeyPlus) = 43
arrKeyHitDown(cKeyInsert) = 20992
arrKeyHitDown(cKeyHome) = 18176
arrKeyHitDown(cKeyPageUp) = 18688
arrKeyHitDown(cKeyDelete) = 21248
arrKeyHitDown(cKeyEnd) = 20224
arrKeyHitDown(cKeyPageDown) = 20736
arrKeyHitDown(cKeyTab) = 9
arrKeyHitDown(cKeyCapsLock) = -30771
arrKeyHitDown(cKeyPrintScreen) = 30771
arrKeyHitDown(cKeyScrollLock) = -145
arrKeyHitDown(cKeyPauseBreak) = 0
arrKeyHitDown(cKeyEnter) = 13
arrKeyHitDown(cKeySquareOpen) = 91
arrKeyHitDown(cKeySquareClose) = 93
arrKeyHitDown(cKeyBackSlash) = 92
arrKeyHitDown(cKeyCurlyOpen) = 123
arrKeyHitDown(cKeyCurlyClose) = 125
arrKeyHitDown(cKeyPipe) = 124
arrKeyHitDown(cKeyComma) = 44
arrKeyHitDown(cKeyPeriod) = 46
arrKeyHitDown(cKeySlash) = 47
arrKeyHitDown(cKeyLt) = 60
arrKeyHitDown(cKeyGt) = 62
arrKeyHitDown(cKeyQuestion) = 63
arrKeyHitDown(cKeySemicolon) = 59
arrKeyHitDown(cKeyApostrophe) = 39
arrKeyHitDown(cKeyColon) = 58
arrKeyHitDown(cKeyQuote) = 34
arrKeyHitDown(cKeyShiftLeft) = 30768
arrKeyHitDown(cKeyShiftRight) = 30769
arrKeyHitDown(cKeyCtrlLeft) = -30766
arrKeyHitDown(cKeyCtrlRight) = -30767
arrKeyHitDown(cKeyAltLeft) = -30764
arrKeyHitDown(cKeyAltRight) = -30765
arrKeyHitDown(cKeyWinLeft) = 0
arrKeyHitDown(cKeyWinRight) = 0
arrKeyHitDown(cKeyMenu) = 0
arrKeyHitDown(cKeySpace) = 32
arrKeyHitDown(cKeyLeftArrow) = 19200
arrKeyHitDown(cKeyUpArrow) = 18432
arrKeyHitDown(cKeyDownArrow) = 20480
arrKeyHitDown(cKeyRightArrow) = 19712
arrKeyHitDown(cKeyNumLock) = 30772
arrKeyHitDown(cKeyA) = 97
arrKeyHitDown(cKeyB) = 98
arrKeyHitDown(cKeyC) = 99
arrKeyHitDown(cKeyD) = 100
arrKeyHitDown(cKeyE) = 101
arrKeyHitDown(cKeyF) = 102
arrKeyHitDown(cKeyG) = 103
arrKeyHitDown(cKeyH) = 104
arrKeyHitDown(cKeyI) = 105
arrKeyHitDown(cKeyJ) = 106
arrKeyHitDown(cKeyK) = 107
arrKeyHitDown(cKeyL) = 108
arrKeyHitDown(cKeyM) = 109
arrKeyHitDown(cKeyN) = 110
arrKeyHitDown(cKeyO) = 111
arrKeyHitDown(cKeyP) = 112
arrKeyHitDown(cKeyQ) = 113
arrKeyHitDown(cKeyR) = 114
arrKeyHitDown(cKeyS) = 115
arrKeyHitDown(cKeyT) = 116
arrKeyHitDown(cKeyU) = 117
arrKeyHitDown(cKeyV) = 118
arrKeyHitDown(cKeyW) = 119
arrKeyHitDown(cKeyX) = 120
arrKeyHitDown(cKeyY) = 121
arrKeyHitDown(cKeyZ) = 122
arrKeyHitDown(cKeyUpperA) = 65
arrKeyHitDown(cKeyUpperB) = 66
arrKeyHitDown(cKeyUpperC) = 67
arrKeyHitDown(cKeyUpperD) = 68
arrKeyHitDown(cKeyUpperE) = 69
arrKeyHitDown(cKeyUpperF) = 70
arrKeyHitDown(cKeyUpperG) = 71
arrKeyHitDown(cKeyUpperH) = 72
arrKeyHitDown(cKeyUpperI) = 73
arrKeyHitDown(cKeyUpperJ) = 74
arrKeyHitDown(cKeyUpperK) = 75
arrKeyHitDown(cKeyUpperL) = 76
arrKeyHitDown(cKeyUpperM) = 77
arrKeyHitDown(cKeyUpperN) = 78
arrKeyHitDown(cKeyUpperO) = 79
arrKeyHitDown(cKeyUpperP) = 80
arrKeyHitDown(cKeyUpperQ) = 81
arrKeyHitDown(cKeyUpperR) = 82
arrKeyHitDown(cKeyUpperS) = 83
arrKeyHitDown(cKeyUpperT) = 84
arrKeyHitDown(cKeyUpperU) = 85
arrKeyHitDown(cKeyUpperV) = 86
arrKeyHitDown(cKeyUpperW) = 87
arrKeyHitDown(cKeyUpperX) = 88
arrKeyHitDown(cKeyUpperY) = 89
arrKeyHitDown(cKeyUpperZ) = 90
arrKeyHitDown(cKeypadSlash) = 0
arrKeyHitDown(cKeypadMultiply) = 0
arrKeyHitDown(cKeypadMinus) = 0
arrKeyHitDown(cKeypad7Home) = 0
arrKeyHitDown(cKeypad8Up) = 0
arrKeyHitDown(cKeypad9PgUp) = 0
arrKeyHitDown(cKeypadPlus) = 0
arrKeyHitDown(cKeypad4Left) = 0
arrKeyHitDown(cKeypad5) = 53
arrKeyHitDown(cKeypad6Right) = 0
arrKeyHitDown(cKeypad1End) = 0
arrKeyHitDown(cKeypad2Down) = 0
arrKeyHitDown(cKeypad3PgDn) = 0
arrKeyHitDown(cKeypadEnter) = 0
arrKeyHitDown(cKeypad0Ins) = 0
arrKeyHitDown(cKeypadPeriodDel) = 0
' Keyup codes for _KeyHit (value of 0 means undetectable or ambiguous, use _BUTTON or other method)
arrKeyHitUp(cKeyEsc) = 27
arrKeyHitUp(cKeyF1) = -15104
arrKeyHitUp(cKeyF2) = -15360
arrKeyHitUp(cKeyF3) = -15616
arrKeyHitUp(cKeyF4) = -15872
arrKeyHitUp(cKeyF5) = -16128
arrKeyHitUp(cKeyF6) = -16384
arrKeyHitUp(cKeyF7) = -16640
arrKeyHitUp(cKeyF8) = -16896
arrKeyHitUp(cKeyF9) = -17152
arrKeyHitUp(cKeyF10) = -17408
arrKeyHitUp(cKeyF11) = 31488
arrKeyHitUp(cKeyF12) = 31232
arrKeyHitUp(cKeyBackTick) = -96
arrKeyHitUp(cKey1) = -49
arrKeyHitUp(cKey2) = -50
arrKeyHitUp(cKey3) = -51
arrKeyHitUp(cKey4) = -52
arrKeyHitUp(cKey5) = -53
arrKeyHitUp(cKey6) = -54
arrKeyHitUp(cKey7) = -55
arrKeyHitUp(cKey8) = -56
arrKeyHitUp(cKey9) = -57
arrKeyHitUp(cKey0) = -48
arrKeyHitUp(cKeyMinus) = -45
arrKeyHitUp(cKeyEqual) = -61
arrKeyHitUp(cKeyBackspace) = -8
arrKeyHitUp(cKeyTilde) = -126
arrKeyHitUp(cKeyExclamation) = -33
arrKeyHitUp(cKeyAt) = -64
arrKeyHitUp(cKeyPound) = -35
arrKeyHitUp(cKeyDollar) = -36
arrKeyHitUp(cKeyPercent) = -37
arrKeyHitUp(cKeyCaret) = -94
arrKeyHitUp(cKeyAmpersand) = -38
arrKeyHitUp(cKeyAsterisk) = -42
arrKeyHitUp(cKeyParenOpen) = -40
arrKeyHitUp(cKeyParenClose) = -41
arrKeyHitUp(cKeyUnderscore) = -95
arrKeyHitUp(cKeyPlus) = -43
arrKeyHitUp(cKeyInsert) = -20992
arrKeyHitUp(cKeyHome) = -18176
arrKeyHitUp(cKeyPageUp) = -18688
arrKeyHitUp(cKeyDelete) = -21248
arrKeyHitUp(cKeyEnd) = -20224
arrKeyHitUp(cKeyPageDown) = -20736
arrKeyHitUp(cKeyTab) = -9
arrKeyHitUp(cKeyCapsLock) = -20
arrKeyHitUp(cKeyPrintScreen) = -44
arrKeyHitUp(cKeyScrollLock) = -145
arrKeyHitUp(cKeyPauseBreak) = 0
arrKeyHitUp(cKeyEnter) = -13
arrKeyHitUp(cKeySquareOpen) = -91
arrKeyHitUp(cKeySquareClose) = -93
arrKeyHitUp(cKeyBackSlash) = -92
arrKeyHitUp(cKeyCurlyOpen) = -123
arrKeyHitUp(cKeyCurlyClose) = -125
arrKeyHitUp(cKeyPipe) = -124
arrKeyHitUp(cKeyComma) = -44
arrKeyHitUp(cKeyPeriod) = -46
arrKeyHitUp(cKeySlash) = -47
arrKeyHitUp(cKeyLt) = -60
arrKeyHitUp(cKeyGt) = -62
arrKeyHitUp(cKeyQuestion) = -63
arrKeyHitUp(cKeySemicolon) = -59
arrKeyHitUp(cKeyApostrophe) = -39
arrKeyHitUp(cKeyColon) = -58
arrKeyHitUp(cKeyQuote) = -34
arrKeyHitUp(cKeyShiftLeft) = -30768
arrKeyHitUp(cKeyShiftRight) = -30769
arrKeyHitUp(cKeyCtrlLeft) = 30766
arrKeyHitUp(cKeyCtrlRight) = 30767
arrKeyHitUp(cKeyAltLeft) = 30764
arrKeyHitUp(cKeyAltRight) = 30765
arrKeyHitUp(cKeyWinLeft) = 0
arrKeyHitUp(cKeyWinRight) = 0
arrKeyHitUp(cKeyMenu) = 0
arrKeyHitUp(cKeySpace) = -32
arrKeyHitUp(cKeyLeftArrow) = -19200
arrKeyHitUp(cKeyUpArrow) = -18432
arrKeyHitUp(cKeyDownArrow) = -20480
arrKeyHitUp(cKeyRightArrow) = -19712
arrKeyHitUp(cKeyNumLock) = -144
arrKeyHitUp(cKeyA) = -97
arrKeyHitUp(cKeyB) = -98
arrKeyHitUp(cKeyC) = -99
arrKeyHitUp(cKeyD) = -100
arrKeyHitUp(cKeyE) = -101
arrKeyHitUp(cKeyF) = -102
arrKeyHitUp(cKeyG) = -103
arrKeyHitUp(cKeyH) = -104
arrKeyHitUp(cKeyI) = -105
arrKeyHitUp(cKeyJ) = -106
arrKeyHitUp(cKeyK) = -107
arrKeyHitUp(cKeyL) = -108
arrKeyHitUp(cKeyM) = -109
arrKeyHitUp(cKeyN) = -110
arrKeyHitUp(cKeyO) = -111
arrKeyHitUp(cKeyP) = -112
arrKeyHitUp(cKeyQ) = -113
arrKeyHitUp(cKeyR) = -114
arrKeyHitUp(cKeyS) = -115
arrKeyHitUp(cKeyT) = -116
arrKeyHitUp(cKeyU) = -117
arrKeyHitUp(cKeyV) = -118
arrKeyHitUp(cKeyW) = -119
arrKeyHitUp(cKeyX) = -120
arrKeyHitUp(cKeyY) = -121
arrKeyHitUp(cKeyZ) = -122
arrKeyHitUp(cKeyUpperA) = -65
arrKeyHitUp(cKeyUpperB) = -66
arrKeyHitUp(cKeyUpperC) = -67
arrKeyHitUp(cKeyUpperD) = -68
arrKeyHitUp(cKeyUpperE) = -69
arrKeyHitUp(cKeyUpperF) = -70
arrKeyHitUp(cKeyUpperG) = -71
arrKeyHitUp(cKeyUpperH) = -72
arrKeyHitUp(cKeyUpperI) = -73
arrKeyHitUp(cKeyUpperJ) = -74
arrKeyHitUp(cKeyUpperK) = -75
arrKeyHitUp(cKeyUpperL) = -76
arrKeyHitUp(cKeyUpperM) = -77
arrKeyHitUp(cKeyUpperN) = -78
arrKeyHitUp(cKeyUpperO) = -79
arrKeyHitUp(cKeyUpperP) = -80
arrKeyHitUp(cKeyUpperQ) = -81
arrKeyHitUp(cKeyUpperR) = -82
arrKeyHitUp(cKeyUpperS) = -83
arrKeyHitUp(cKeyUpperT) = -84
arrKeyHitUp(cKeyUpperU) = -85
arrKeyHitUp(cKeyUpperV) = -86
arrKeyHitUp(cKeyUpperW) = -87
arrKeyHitUp(cKeyUpperX) = -88
arrKeyHitUp(cKeyUpperY) = -89
arrKeyHitUp(cKeyUpperZ) = -90
arrKeyHitUp(cKeypadSlash) = 0
arrKeyHitUp(cKeypadMultiply) = 0
arrKeyHitUp(cKeypadMinus) = 0
arrKeyHitUp(cKeypad7Home) = 0
arrKeyHitUp(cKeypad8Up) = 0
arrKeyHitUp(cKeypad9PgUp) = 0
arrKeyHitUp(cKeypadPlus) = 0
arrKeyHitUp(cKeypad4Left) = 0
arrKeyHitUp(cKeypad5) = -53
arrKeyHitUp(cKeypad6Right) = 0
arrKeyHitUp(cKeypad1End) = 0
arrKeyHitUp(cKeypad2Down) = 0
arrKeyHitUp(cKeypad3PgDn) = 0
arrKeyHitUp(cKeypadEnter) = 0
arrKeyHitUp(cKeypad0Ins) = 0
arrKeyHitUp(cKeypadPeriodDel) = 0
' Keyboard codes for _BUTTON (value of 0 means undetectable, use _KEYHIT or other method)
arrButton(cKeyEsc) = 2
arrButton(cKeyF1) = 60
arrButton(cKeyF2) = 61
arrButton(cKeyF3) = 62
arrButton(cKeyF4) = 63
arrButton(cKeyF5) = 64
arrButton(cKeyF6) = 65
arrButton(cKeyF7) = 66
arrButton(cKeyF8) = 67
arrButton(cKeyF9) = 68
arrButton(cKeyF10) = 0 ' detect with _KEYHIT
arrButton(cKeyF11) = 88
arrButton(cKeyF12) = 89
arrButton(cKeyBackTick) = 42
arrButton(cKey1) = 3
arrButton(cKey2) = 4
arrButton(cKey3) = 5
arrButton(cKey4) = 6
arrButton(cKey5) = 7
arrButton(cKey6) = 8
arrButton(cKey7) = 9
arrButton(cKey8) = 10
arrButton(cKey9) = 11
arrButton(cKey0) = 12
arrButton(cKeyMinus) = 13
arrButton(cKeyEqual) = 14
arrButton(cKeyBackspace) = 15
arrButton(cKeyTilde) = 42
arrButton(cKeyExclamation) = 3
arrButton(cKeyAt) = 4
arrButton(cKeyPound) = 5
arrButton(cKeyDollar) = 6
arrButton(cKeyPercent) = 7
arrButton(cKeyCaret) = 8
arrButton(cKeyAmpersand) = 9
arrButton(cKeyAsterisk) = 10
arrButton(cKeyParenOpen) = 11
arrButton(cKeyParenClose) = 12
arrButton(cKeyUnderscore) = 13
arrButton(cKeyPlus) = 14
arrButton(cKeyInsert) = 339
arrButton(cKeyHome) = 328
arrButton(cKeyPageUp) = 330
arrButton(cKeyDelete) = 340
arrButton(cKeyEnd) = 336
arrButton(cKeyPageDown) = 338
arrButton(cKeyTab) = 16
arrButton(cKeyCapsLock) = 59
arrButton(cKeyPrintScreen) = 0 ' detect with _KEYHIT
arrButton(cKeyScrollLock) = 71
arrButton(cKeyPauseBreak) = 0 ' detect with _KEYHIT
arrButton(cKeyEnter) = 29
arrButton(cKeySquareOpen) = 27
arrButton(cKeySquareClose) = 28
arrButton(cKeyBackSlash) = 44
arrButton(cKeyCurlyOpen) = 27
arrButton(cKeyCurlyClose) = 28
arrButton(cKeyPipe) = 44
arrButton(cKeyComma) = 52
arrButton(cKeyPeriod) = 53
arrButton(cKeySlash) = 54
arrButton(cKeyLt) = 52
arrButton(cKeyGt) = 53
arrButton(cKeyQuestion) = 54
arrButton(cKeySemicolon) = 40
arrButton(cKeyApostrophe) = 41
arrButton(cKeyColon) = 40
arrButton(cKeyQuote) = 41
arrButton(cKeyShiftLeft) = 43
arrButton(cKeyShiftRight) = 55
arrButton(cKeyCtrlLeft) = 30
arrButton(cKeyCtrlRight) = 286
arrButton(cKeyAltLeft) = 0 ' detect with _KEYHIT
arrButton(cKeyAltRight) = 0 ' detect with _KEYHIT
arrButton(cKeyWinLeft) = 348
arrButton(cKeyWinRight) = 349
arrButton(cKeyMenu) = 350
arrButton(cKeySpace) = 58
arrButton(cKeyLeftArrow) = 332
arrButton(cKeyUpArrow) = 329
arrButton(cKeyDownArrow) = 337
arrButton(cKeyRightArrow) = 334
arrButton(cKeyNumLock) = 326
arrButton(cKeyA) = 31
arrButton(cKeyB) = 49
arrButton(cKeyC) = 47
arrButton(cKeyD) = 33
arrButton(cKeyE) = 19
arrButton(cKeyF) = 34
arrButton(cKeyG) = 35
arrButton(cKeyH) = 36
arrButton(cKeyI) = 24
arrButton(cKeyJ) = 37
arrButton(cKeyK) = 38
arrButton(cKeyL) = 39
arrButton(cKeyM) = 51
arrButton(cKeyN) = 50
arrButton(cKeyO) = 25
arrButton(cKeyP) = 26
arrButton(cKeyQ) = 17
arrButton(cKeyR) = 20
arrButton(cKeyS) = 32
arrButton(cKeyT) = 21
arrButton(cKeyU) = 23
arrButton(cKeyV) = 48
arrButton(cKeyW) = 18
arrButton(cKeyX) = 46
arrButton(cKeyY) = 22
arrButton(cKeyZ) = 45
arrButton(cKeyUpperA) = 31
arrButton(cKeyUpperB) = 49
arrButton(cKeyUpperC) = 47
arrButton(cKeyUpperD) = 33
arrButton(cKeyUpperE) = 19
arrButton(cKeyUpperF) = 34
arrButton(cKeyUpperG) = 35
arrButton(cKeyUpperH) = 36
arrButton(cKeyUpperI) = 24
arrButton(cKeyUpperJ) = 37
arrButton(cKeyUpperK) = 38
arrButton(cKeyUpperL) = 39
arrButton(cKeyUpperM) = 51
arrButton(cKeyUpperN) = 50
arrButton(cKeyUpperO) = 25
arrButton(cKeyUpperP) = 26
arrButton(cKeyUpperQ) = 17
arrButton(cKeyUpperR) = 20
arrButton(cKeyUpperS) = 32
arrButton(cKeyUpperT) = 21
arrButton(cKeyUpperU) = 23
arrButton(cKeyUpperV) = 48
arrButton(cKeyUpperW) = 18
arrButton(cKeyUpperX) = 46
arrButton(cKeyUpperY) = 22
arrButton(cKeyUpperZ) = 45
arrButton(cKeypadSlash) = 310
arrButton(cKeypadMultiply) = 56
arrButton(cKeypadMinus) = 75
arrButton(cKeypad7Home) = 72
arrButton(cKeypad8Up) = 73
arrButton(cKeypad9PgUp) = 74
arrButton(cKeypadPlus) = 79
arrButton(cKeypad4Left) = 76
arrButton(cKeypad5) = 77
arrButton(cKeypad6Right) = 78
arrButton(cKeypad1End) = 80
arrButton(cKeypad2Down) = 81
arrButton(cKeypad3PgDn) = 82
arrButton(cKeypadEnter) = 285
arrButton(cKeypad0Ins) = 83
arrButton(cKeypadPeriodDel) = 84
' Track key state
Dim index As Long
For index = LBound(arrKeyState) To UBound(arrKeyState)
arrKeyState(index) = _FALSE
Next index
End Sub ' InitKeyCodes
' ****************************************************************************************************************************************************************
' BEGIN COPY LINES BETWEEN <header> and </header> TO NEW FILE, UNCOMMENT AND SAVE AS "QB_Sheets.h" TO SAME FOLDER AS MAIN PROGRAM
' ****************************************************************************************************************************************************************
'<header>
'// Header for Grid Logic and C++ Interface
'#ifndef QB_SHEETS_H
'#define QB_SHEETS_H
'
'#include <vector>
'#include <string>
'#include <fstream>
'#include <cstdint>
'
'extern "C" {
' typedef intptr_t QBSHandle;
'
' // Internal cell storage structure
' struct QBCell {
' std::string s;
' int64_t i = 0;
' double d = 0.0;
' uint8_t type = 0; // 0:Empty, 1:Str, 2:Int, 3:Dbl
' uint32_t bg = 0xFFFFFFFF; // Opaque White
' uint32_t fg = 0xFF000000; // Opaque Black
' bool lock = false;
' };
'
' // Fast-fetch structure for QB64 (binary compatible)
' struct QBCellInfo {
' uint32_t bg = 0xFFFFFFFF; // Opaque White
' uint32_t fg = 0xFF000000; // Opaque Black
' bool lock;
' uint8_t varType;
' };
'
' struct QBRow {
' int16_t height = 20;
' std::vector<QBCell> cells;
' };
'
' struct QBSheet {
' std::vector<QBRow> rows;
' std::vector<int16_t> colWidths;
' };
'
' // --- Lifecycle Management ---
' __declspec(dllexport) QBSHandle QBS_New(int r, int c) {
' QBSheet* s = new QBSheet();
' s->rows.resize(r);
' for (int i = 0; i < r; ++i) s->rows[i].cells.resize(c);
' s->colWidths.assign(c, 100);
' return (QBSHandle)s;
' }
'
' __declspec(dllexport) void QBS_Free(QBSHandle h) {
' delete (QBSheet*)h;
' }
'
' // --- Universal Data Setters ---
' __declspec(dllexport) void QBS_SetStr(QBSHandle h, int r, int c, const char* v) {
' auto* s = (QBSheet*)h;
' if (s && r < s->rows.size() && c < s->rows[r].cells.size()) {
' s->rows[r].cells[c].s = v; s->rows[r].cells[c].type = 1;
' }
' }
' __declspec(dllexport) void QBS_SetInt(QBSHandle h, int r, int c, int64_t v) {
' auto* s = (QBSheet*)h;
' if (s && r < s->rows.size() && c < s->rows[r].cells.size()) {
' s->rows[r].cells[c].i = v; s->rows[r].cells[c].type = 2;
' }
' }
' __declspec(dllexport) void QBS_SetDbl(QBSHandle h, int r, int c, double v) {
' auto* s = (QBSheet*)h;
' if (s && r < s->rows.size() && c < s->rows[r].cells.size()) {
' s->rows[r].cells[c].d = v; s->rows[r].cells[c].type = 3;
' }
' }
'
' // --- Universal Data Getters ---
' __declspec(dllexport) const char* QBS_GetStr(QBSHandle h, int r, int c) {
' auto* s = (QBSheet*)h;
' if (!s || r >= s->rows.size() || c >= s->rows[r].cells.size()) return "";
' return s->rows[r].cells[c].s.c_str();
' }
' __declspec(dllexport) int64_t QBS_GetInt(QBSHandle h, int r, int c) {
' auto* s = (QBSheet*)h;
' return (s && r < s->rows.size() && c < s->rows[r].cells.size()) ? s->rows[r].cells[c].i : 0;
' }
' __declspec(dllexport) double QBS_GetDbl(QBSHandle h, int r, int c) {
' auto* s = (QBSheet*)h;
' return (s && r < s->rows.size() && c < s->rows[r].cells.size()) ? s->rows[r].cells[c].d : 0.0;
' }
'
' // --- High-Speed Info Fetch ---
' // Update this function in QB_Sheets.h
' __declspec(dllexport) void QBS_GetInfo(QBSHandle h, int r, int c, intptr_t infoPtr) {
' auto* s = (QBSheet*)h;
' if (s && r < s->rows.size() && c < s->rows[r].cells.size()) {
' // Cast the raw address back to our struct type
' QBCellInfo* info = (QBCellInfo*)infoPtr;
' auto& cell = s->rows[r].cells[c];
' info->bg = cell.bg;
' info->fg = cell.fg;
' info->lock = cell.lock;
' info->varType = cell.type;
' }
' }
' // --- Formatting & Layout ---
' __declspec(dllexport) void QBS_Format(QBSHandle h, int r, int c, uint32_t bg, uint32_t fg, bool lock) {
' auto* s = (QBSheet*)h;
' if (s && r < s->rows.size() && c < s->rows[r].cells.size()) {
' auto& cell = s->rows[r].cells[c];
' cell.bg = bg; cell.fg = fg; cell.lock = lock;
' }
' }
'
' __declspec(dllexport) void QBS_Size(QBSHandle h, int idx, int size, bool isRow) {
' auto* s = (QBSheet*)h; if (!s) return;
' if (isRow && idx < s->rows.size()) s->rows[idx].height = (int16_t)size;
' else if (!isRow && idx < s->colWidths.size()) s->colWidths[idx] = (int16_t)size;
' }
'
' __declspec(dllexport) int QBS_GetSize(QBSHandle h, int idx, bool isRow) {
' auto* s = (QBSheet*)h; if (!s) return 0;
' return isRow ? s->rows[idx].height : s->colWidths[idx];
' }
'
' // --- Persistence (Binary Save/Load) ---
' __declspec(dllexport) int QBS_Save(QBSHandle h, const char* filename) {
' auto* s = (QBSheet*)h;
' std::ofstream ofs(filename, std::ios::binary);
' if (!ofs) return 0;
' uint32_t rows = s->rows.size(), cols = s->colWidths.size();
' ofs.write((char*)&rows, 4); ofs.write((char*)&cols, 4);
' for (auto w : s->colWidths) ofs.write((char*)&w, 2);
' for (auto& r : s->rows) {
' ofs.write((char*)&r.height, 2);
' for (auto& c : r.cells) {
' ofs.write((char*)&c.type, 1); ofs.write((char*)&c.bg, 4);
' ofs.write((char*)&c.fg, 4); ofs.write((char*)&c.lock, 1);
' ofs.write((char*)&c.i, 8); ofs.write((char*)&c.d, 8);
' uint32_t slen = c.s.size(); ofs.write((char*)&slen, 4);
' ofs.write(c.s.data(), slen);
' }
' }
' return 1;
' }
'
' __declspec(dllexport) QBSHandle QBS_Load(const char* filename) {
' std::ifstream ifs(filename, std::ios::binary);
' if (!ifs) return 0;
' uint32_t rows, cols;
' ifs.read((char*)&rows, 4); ifs.read((char*)&cols, 4);
' QBSheet* s = new QBSheet();
' s->rows.resize(rows); s->colWidths.resize(cols);
' for (int i = 0; i < cols; ++i) ifs.read((char*)&s->colWidths[i], 2);
' for (int i = 0; i < rows; ++i) {
' s->rows[i].cells.resize(cols);
' ifs.read((char*)&s->rows[i].height, 2);
' for (int j = 0; j < cols; ++j) {
' auto& c = s->rows[i].cells[j];
' ifs.read((char*)&c.type, 1); ifs.read((char*)&c.bg, 4);
' ifs.read((char*)&c.fg, 4); ifs.read((char*)&c.lock, 1);
' ifs.read((char*)&c.i, 8); ifs.read((char*)&c.d, 8);
' uint32_t slen; ifs.read((char*)&slen, 4);
' c.s.resize(slen); ifs.read(&c.s[0], slen);
' }
' }
' return (QBSHandle)s;
' }
'}
'#endif
'</header>
' ****************************************************************************************************************************************************************
' END COPY LINES BETWEEN <header> and </header> TO NEW FILE, UNCOMMENT AND SAVE AS "QB_Sheets.h" TO SAME FOLDER AS MAIN PROGRAM
' ****************************************************************************************************************************************************************
Posts: 346
Threads: 45
Joined: Jun 2024
Reputation:
32
@madscijr
First i'd say use inform to do you GUI aspects. Then we can look at implementing Tabs for multiple sheets (the c++ back end already supports this). Date and time fields can be stored in the string data but a few new flags to denote the extended data type's would be useful (varType in the Cell data udt(need to add em to both the c++ and the Qb64 side)). Current max for cols/rows is 1000000 i think but you can change that value in the HandleGrid sub to use new ones stored in the Grid udt. The only limit to the number of cells is based on your ram so the sheets can be as big as you want/need/can accommodate.
Good luck and happy coding.
Unseen
Posts: 1,215
Threads: 162
Joined: Apr 2022
Reputation:
34
Thanks, I've been meaning to play with InForm for a while, this could very well be a good project to finally get my feet wet...
Posts: 4,692
Threads: 222
Joined: Apr 2022
Reputation:
322
01-29-2026, 01:09 PM
(This post was last modified: 01-29-2026, 02:11 PM by bplus.)
@madscijr
OMG dont even try such a complex thing to get your feet wet with InForm!
Start by learning to use Textboxes after Buttons, all the control tools first! because the ListBox is what you will need for this spreadsheet stuff and that takes some learning just in itself as arrays dont fit in UDT's for Controls so you have to figure out how all that works. Dont let your eyes get bigger that your brain digestion.
The Spreadsheet thing is a great goal, a "Why learn InForm anyway?" Answer.
Learning anything takes focus and a good strong Why! for that focus, unless you are a freak'n genius that can pickup things on first exposure and honestly not seeing that in your coding style, yet!
724 855 599 923 575 468 400 206 147 564 878 823 652 556 bxor cross forever
Posts: 1,215
Threads: 162
Joined: Apr 2022
Reputation:
34
01-29-2026, 02:13 PM
(This post was last modified: 01-29-2026, 02:16 PM by madscijr.)
Sounds reasonable... My eyes are often bigger than my stomach where projects are concerned... The more I think about it, the more it seems I bit off more than I can chew... Feel free to play with the spreadsheet, it will probably take a team of people to whip into shape! For now, I'm just happy to have this grid control, and @Petr's non-GUI version with its working calculations can come in handy too... Next stop for me is to try playing with InForm... Is there a guide for dummies for that? I mean real basic, like hello world basic... "download x file from {url}, put it in y folder with your code, then make a new .bas with z code in it"... because I find it kinda intimidating. One big reason I like QB64 is it's all just one EXE and works right out of the box, no setup necessary. It's stuff with tricky or tedious little details that trips me up when getting into new things, for example Free Basic and Free Pascal seemed a little complicated to set up and Linux led down so many rabbit holes and I burned a lot of time there... Anyway enough yapping, I'll go check out InForm soon!
Posts: 4,692
Threads: 222
Joined: Apr 2022
Reputation:
322
01-29-2026, 02:31 PM
(This post was last modified: 01-29-2026, 04:36 PM by bplus.)
Each control is described in detail in the help just at the place you download the InForm code like QB64 command words in Wiki but it is up to you to put the controls together to work with each other and QB64 code.
That is another aspect to InForm and GUI apps.
The Form designer that helps you visualize the layout of your controls, that will be your introduction when you start practice with Buttons and TextBoxes. I don't know if there is a tut for that but it's pretty intuitive when you are inside the designer.
724 855 599 923 575 468 400 206 147 564 878 823 652 556 bxor cross forever
Posts: 1,215
Threads: 162
Joined: Apr 2022
Reputation:
34
|