Made this because.... well just because. While this loads the table data from a json string, it's simple enough to build it however you want. Because drawing commands by default are drawn last over sprites and text, I opted to use a sprite for the background and window header. You can move the window by dragging the header, resize the window (drag lower right corner) and columns, and scroll using the mouse or dragging the scrollbar. Though as I write this I just remembered it only does vertical scrolling, I forgot to implement horizontal....
I designed it to make it somewhat easy to change themes of the window.
+ Code SnippetSetErrorMode(2)
SetWindowSize( 1024, 768, 0 )
SetVirtualResolution( 1024, 768 )
SetSyncRate( 60, 0 )
UseNewDefaultFonts( 1 )
Type DataTable
x as float
y as float
width as float
height as float
cols as integer
rows as integer
data as integer[-1,-1]
voffset as float
EndType
Type TableColumn
width as integer
sort as integer
textId as integer
name as string
EndType
c = makeColor(255,0,0)
jj$ = '[["Hester Randolph","pink","summer","swifty","046c55ed-dfe0-4d08-8461-ed8d44ac4100"],["Vilma Sears","red","spring","swifty","8f4df59b-3bc9-4502-9c80-50674c64d10e"],["Lynn Morris","pink","spring","rap","723bdf6c-c34c-4527-8001-40ef4fee5c3e"],["Clark Hale","blue","spring","folk","72d3c74b-c4ca-40fc-8136-0ec93328e836"],["Suzanne Cleveland","red","spring","swifty","75761958-ff38-45ae-80e9-8da2eb676518"],["Jones Rollins","blue","Fall","swifty","4be68612-d026-463f-88dc-4a51ddacf737"],["Kinney Collier","turquoise","Fall","rap","318fdcb4-0fa8-4a84-bc67-38917d4edfd5"],["Mona Snow","brown","spring","blues/jazz","9c7fc70b-87b7-4ea6-8df4-def1f4e28d54"]]'
Type Table_Skin
bgColor as integer // background color
borderColor as integer // border/grid color
` altColor as integer // alternate row color
` altRows as integer // 1 to alternate row colors
headHeight as integer // height of column headers
titleHeight as integer // height of title bar
trackWidth as integer // width of vertical scroll bar track
trackColor as integer
thumbColor as integer
EndType
defaultSkin as Table_Skin
defaultSkin.bgColor = 0xAA4b433b // ABGR
defaultSkin.borderColor = 0xFF6a5d51
defaultSkin.headHeight = 24
defaultSkin.titleHeight = 20
defaultSkin.trackWidth = 14
defaultSkin.trackColor = makeColor(38,48,53)
defaultSkin.thumbColor = 0xFF6a5d51
Type Table
x as integer
y as integer
padding as integer
voffset as float
width as integer
height as integer
columns as TableColumn[]
cells as integer[]
skin as Table_Skin
dragCol as integer
dragOffsetX as integer
dragBase as integer
minColWidth as integer
ox as float // used to store offset when dragging gui components
oy as float // used to store offset when dragging gui components
vScroll as integer // 1 if showing vertical scrollbar
vx as integer //
vy as integer // vertical thumb position (relative to track)
z as float // used for smooth mouse wheel scrolling
lmb as integer // left mouse button status
dragging as integer // flag for dragging column widths
moveTable as integer // flag for moving window
resizeTable as integer // flag for resizing table
vscrolling as integer // flag for vertical scroll bar
bgSpr as integer // window background sprite
titleSpr as integer // window title bar sprite
EndType
t.dragging = 0
t.moveTable = 0
t.resizeTable = 0
t.vscrolling = 0
t as Table
t.skin = defaultSkin
t.x = 250
t.y = 200
t.width = 400
t.height = 200
t.minColWidth = 10
t.padding = 4
t.vScroll = 1
addColumn(t, "Name")
addColumn(t, "Color")
addColumn(t, "Season")
addColumn(t, "Music Genre")
addColumn(t, "More Stuff")
addDataFromJSON(t, jj$)
addDataFromJSON(t, jj$)
t.bgSpr = createSprite(0)
setSpriteColor(t.bgSpr, 59,67,76,255)
setSpriteSize(t.bgSpr, t.width, t.height)
setSpritePosition(t.bgSpr, t.x, t.y)
t.titleSpr = createSprite(0)
setSpriteSize(t.titleSpr, t.width, t.skin.titleHeight)
setSpriteColor(t.titleSpr, 81,93,106,255)
setSpritePosition(t.titleSpr, t.x, t.y)
data as string[0,0]
data.fromJSON(jj$)
do
updateTable(t)
Sync()
loop
function updateTable(t ref as Table)
rowCount = (t.cells.length+1) / (t.columns.length+1)
totalHeight = rowCount*16
viewportHeight# = t.height - t.skin.headHeight - t.skin.titleHeight
thumbHeight = viewportHeight# * (viewportHeight# / totalHeight)
if thumbHeight >= viewportHeight#
t.vScroll = 0
else
t.vScroll = 1
endif
/* Start vertical scrolling */
z = floor(GetRawMouseWheelDelta())
if z
if z < 0 // scroll down
t.z = -4.0
else // scroll up
t.z = 4.0
endif
endif
if t.z <> 0
if t.z < 0
inc t.z, 0.2
if t.z > 0 then t.z = 0
else
dec t.z, 0.2
if t.z < 0 then t.z = 0
endif
setVerticalThumb(t, t.vy-t.z)
endif
/* End vertical scrolling */
// clear flags on mouse up
t.lmb = getRawMouseLeftState()
if t.lmb = 0
t.dragging = 0
t.moveTable = 0
t.resizeTable = 0
t.vscrolling = 0
endif
// if left mouse pressed, check if its in a component trigger area
if getRawMouseLeftPressed()
mx = getRawMouseX()
my = getRawMouseY()
thumbY = t.y+t.skin.titleHeight+t.skin.headheight + t.vy
// titlebar
if mx > t.x and mx < t.x+t.width and my > t.y and my < t.y+t.skin.titleHeight
t.moveTable = 1
t.ox = mx - t.x
t.oy = my - t.y
// lower-right corner (resize)
elseif abs(mx - (t.x+t.width)) < 5 and abs(my - (t.y+t.height)) < 5
t.resizeTable = 1
t.ox = mx - (t.x+t.width)
t.oy = my - (t.y+t.height)
// vertical scroll thumb
elseif t.vScroll = 1 and mx > t.x+t.width-t.skin.trackWidth and mx < t.x+t.width and my > thumbY and my < thumbY+thumbHeight
t.vscrolling = 1
t.oy = my - thumbY
endif
endif
// Handle different component drag events
if t.resizeTable = 1
t.width = getRawMouseX() - t.x - t.ox
t.height = getRawMouseY() - t.y - t.oy
// minimum window size
if t.width < 100 then t.width = 100
if t.height < 60 then t.height = 60
setVerticalThumb(t, t.vy)
setSpriteSize(t.bgSpr, t.width, t.height)
setSpriteSize(t.titleSpr, t.width, t.skin.titleHeight)
refactorTable(t)
elseif t.vscrolling = 1
setVerticalThumb(t, getRawMouseY() - (t.y+t.skin.titleHeight+t.skin.headheight) - t.oy)
elseif t.moveTable = 1
t.x = getRawMouseX() - t.ox
t.y = getRawMouseY() - t.oy
setSpritePosition(t.bgSpr, t.x, t.y)
setSpritePosition(t.titleSpr, t.x, t.y)
refactorTable(t)
elseif t.dragging = 1
// udpate width of dragging column and do boundary check
t.columns[t.dragCol].width = getRawMouseX() - t.dragBase - t.dragOffsetX
if t.columns[t.dragCol].width < t.minColWidth then t.columns[t.dragCol].width = t.minColWidth
refactorTable(t)
elseif t.lmb = 1
x = t.x
for i = 0 to t.columns.length-1
x = x + t.columns[i].width
if getRawMouseY() > t.y+t.skin.titleHeight and getRawMouseY() < t.y+t.height
if abs(getRawMouseX()-x) < 4 // mouse within 4px of column line
t.dragging = 1
t.dragOffsetX = getRawMouseX() - x
t.dragCol = i
t.dragBase = x - t.columns[i].width
endif
endif
next i
endif
drawTable(t)
endfunction
/**
* Handles the 2d drawing routines,
* must be called on every sync
*/
function drawTable(t ref as Table)
x = t.x + t.width - t.skin.trackWidth
y = t.y+t.skin.titleHeight+t.skin.headHeight+1
rowCount = (t.cells.length+1) / (t.columns.length+1)
totalHeight = rowCount*16
viewportHeight# = t.height - t.skin.headHeight - t.skin.titleHeight
thumbHeight = viewportHeight# * (viewportHeight# / totalHeight)
// vertical scrollbar
if t.vScroll = 1
drawBox(x, y, x+t.skin.trackWidth, t.y+t.height, t.skin.trackColor,t.skin.trackColor,t.skin.trackColor,t.skin.trackColor,1) // track
drawBox(x, y+t.vy, x+t.skin.trackWidth, y+t.vy+thumbHeight-1, t.skin.thumbColor,t.skin.thumbColor,t.skin.thumbColor,t.skin.thumbColor,1) // thumb
`drawLine(x, y, x, t.y+t.height, t.skin.borderColor, t.skin.borderColor)
endif
// column headers
drawLine(t.x, t.y+t.skin.titleHeight+t.skin.headHeight, t.x+t.width, t.y+t.skin.titleHeight+t.skin.headHeight, t.skin.borderColor, t.skin.borderColor)
// title bar
drawLine(t.x, t.y+t.skin.titleHeight, t.x+t.width, t.y+t.skin.titleHeight, t.skin.borderColor, t.skin.borderColor)
// window border
drawBox(t.x, t.y, t.x+t.width, t.y+t.height, t.skin.borderColor,t.skin.borderColor,t.skin.borderColor,t.skin.borderColor, 0)
// column lines
x = t.x
for i = 0 to t.columns.length-1
x = x + t.columns[i].width
if x < t.x+t.width
drawLine(x, t.y+t.skin.titleHeight+1, x, t.y+t.skin.titleHeight+(t.height-t.skin.titleHeight), t.skin.borderColor,t.skin.borderColor)
endif
next i
endfunction
function refactorTable(t ref as Table)
// total number of rows
rowCount = (t.cells.length+1) / (t.columns.length+1)
// if showing vertical track bar, prevent text from showing over it
if t.vScroll = 1
maxX = t.x + t.width - t.skin.trackWidth
else
maxX = t.x + t.width
endif
// loop over rows, updating text positions and
for row = 0 to rowCount-1
x = t.x
y = t.y + t.skin.titleHeight + t.skin.headheight + row*16 + t.voffset
for col = 0 to t.columns.length
id = row * (t.columns.length+1) + col
if col > 0 then x = x + t.columns[col-1].width
setTextPosition(t.cells[id], x+t.padding, y)
x2 = tmx_min(x + t.columns[col].width, maxX)
y2 = tmx_min(y + 16, t.y+t.height-1)
y1 = tmx_max(y, t.y+t.skin.titleHeight+t.skin.headHeight)
if col = t.columns.length then x2 = tmx_max(x2, maxX)
setTextScissor(t.cells[id], x+t.padding, y1, x2-t.padding, y2)
next col
next row
// column headers
x = t.x
for col = 0 to t.columns.length
setTextPosition(t.columns[col].textId, x+t.padding, t.y+t.skin.titleHeight+4)
x2 = tmx_min(x+t.columns[col].width, t.x+t.width)
if col = t.columns.length then x2 = tmx_max(x2, t.x+t.width)
setTextScissor(t.columns[col].textId, x+t.padding, t.y+t.skin.titleHeight, x2-t.padding, t.y+t.skin.titleHeight+t.skin.headHeight)
x = x + t.columns[col].width
next col
endfunction
function setVerticalThumb(t ref as Table, v as float)
rowCount = (t.cells.length+1) / (t.columns.length+1)
totalHeight = rowCount*16
viewportHeight# = t.height - t.skin.headHeight - t.skin.titleHeight // visible area
thumbHeight = viewportHeight# * (viewportHeight# / totalHeight)
if thumbHeight < viewportHeight#
t.vy = v
if t.vy > viewportHeight# - thumbHeight then t.vy = viewportHeight# - thumbHeight
if t.vy < 0 then t.vy = 0
d# = viewportHeight# - thumbHeight
p# = t.vy / d#
t.voffset = -(totalHeight - viewportHeight#) * p#
endif
refactorTable(t)
endfunction
function addColumn(t ref as Table, colName as string)
c as TableColumn
c.textId = createText(colName)
setTextSize(c.textId, 16)
c.width = 50
x = t.x
for i = 0 to t.columns.length
x = x + c.width
next i
setTextPosition(c.textId, x, t.y)
t.columns.insert(c)
endfunction
function tmx_min(n1, n2)
if n1 > n2 then exitfunction n2
endfunction n1
function tmx_max(n1, n2)
if n1 > n2 then exitfunction n1
endfunction n2
function addDataFromJSON(t ref as Table, json as string)
rowCount = (t.cells.length+1) / (t.columns.length+1)
offsetY = rowCount * 16
data as string[0,0]
data.fromJSON(json)
dl = (data.length+1)*(data[0].length+1)
startIndex = t.cells.length + 1
t.cells.length = t.cells.length + dl
for row = 0 to data.length
x = 0
w = 0
for j = 0 to data[row].length
id = row * (data[0].length+1) + j + startIndex
t.cells[id] = createText(data[row,j])
setTextSize(t.cells[id], 16)
setTextDepth(t.cells[id], 2)
y = t.y + row*16 + offsetY
if j > 0 then w = t.columns[j-1].width
x = j*50
setTextPosition(t.cells[id], x, y)
setTextScissor(t.cells[id], x, y, x+t.columns[j].width, y+16)
next j
next row
refactorTable(t)
endfunction