Skip to content

Commit

Permalink
Added WhiteBoard widget. Fixed multiline for labels and buttons
Browse files Browse the repository at this point in the history
  • Loading branch information
immortalx74 committed Nov 4, 2022
1 parent cd48c11 commit 4a07fd4
Show file tree
Hide file tree
Showing 3 changed files with 183 additions and 8 deletions.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
- TabBar
- Dummy
- ProgressBar
- WhiteBoard

---
`UI.Button(text, width, height)`
Expand All @@ -52,6 +53,18 @@ NOTE: if no `width` and/or `height` are provided, the button size will be auto-

<span style="color:DeepSkyBlue">Returns:</span> `boolean` , true when clicked.

---
`UI.WhiteBoard(name, width, height)`
|Argument|Type|Description
|:---|:---|:---|
|`name`|string|whiteboard ID
|`width`|number|width in pixels
|`height`|number|height in pixels

<span style="color:DeepSkyBlue">Returns:</span> `Pass`, `boolean`, `boolean`, `boolean`, `boolean`, `number`, `number`, [1] Pass object, [2] clicked, [3] down, [4] released, [5] hovered, [6] X, [7] Y
NOTE: General purpose widget for custom drawing/interaction. The returned Pass can be used to do regular LÖVR draw-commands
like plane, circle, text, etc. X and Y are the local 2D coordinates of the pointer (0,0 is top,left)

---
`UI.TextBox(name, num_chars, buffer)`
|Argument|Type|Description
Expand Down
84 changes: 83 additions & 1 deletion main.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
-- NOTE: This demo app is currently completely unstructured, crude and lacks comments.
-- This will be addressed. For the time being it's a testbed during development.

UI = require "ui/ui"
buf = "John"
win2pos = lovr.math.newMat4( 0.1, 1.3, -1.3 )
Expand All @@ -12,7 +15,23 @@ tab_bar_idx = 1
col_list_idx = 1
progress_value = 0
accumulator = 0
time_now = 0
planes = { m = {}, col = {} }
plane_frames = 0
amplitude = 100
frequency = 0.1
zoom = 1

local x, y, a, c1, c2, c3
for i = 1, 10 do
x = lovr.math.random( 0, 500 )
y = lovr.math.random( 0, 300 )
a = lovr.math.random( 0, math.pi * 2 )
c1 = lovr.math.random()
c2 = lovr.math.random()
c3 = lovr.math.random()
table.insert( planes.m, lovr.math.newMat4( vec3( x, y, 0 ), vec3( 100 ), quat( a, 0, 0, 1 ) ) )
table.insert( planes.col, { c1, c2, c3 } )
end

-- Override only some colors
custom_theme =
Expand Down Expand Up @@ -42,6 +61,23 @@ function lovr.update( dt )
progress_value = 0
accumulator = 0
end

if plane_frames < 10 then
plane_frames = plane_frames + 1
else
plane_frames = 0
local x, y, a, c1, c2, c3
for i = 1, 10 do
x = lovr.math.random( 0, 500 )
y = lovr.math.random( 0, 300 )
a = lovr.math.random( 0, math.pi * 2 )
c1 = lovr.math.random()
c2 = lovr.math.random()
c3 = lovr.math.random()
planes.m[ i ]:set( vec3( x, y, 0 ), vec3( zoom * 100 ), quat( a, 0, 0, 1 ) )
planes.col[ i ] = { c1, c2, c3 }
end
end
end

function lovr.draw( pass )
Expand Down Expand Up @@ -108,6 +144,52 @@ function lovr.draw( pass )
UI.Begin( "SecondWindow", win2pos )
UI.TextBox( "Location", 20, "" )
if UI.Button( "AhOh" ) then print( UI.GetWindowSize( "FirstWindow" ) ) end

-- whiteboard 1
UI.Label( "Click & drag R/L to zoom in/out:" )
local ps, clicked, down, released, hovered, lx, ly = UI.WhiteBoard( "WhiteBoard1", 500, 300 )
ps:setColor( 0, 0, 0 )
ps:fill()

if down then
zoom = (lx * 0.01)
end

for i = 1, 10 do
ps:setColor( planes.col[ i ] )
ps:plane( planes.m[ i ] )
end

-- whiteboard 2
UI.Label( "Use the sliders or \nclick & drag on waveform:" )
local ps, clicked, down, released, hovered, lx, ly = UI.WhiteBoard( "WhiteBoard2", 500, 300 )
if down then
-- amplitude = -(ly / 2)
amplitude = (150 * ly) / 300
frequency = (0.2 * lx) / 500
end
if hovered then
ps:setColor( 0.1, 0, 0.2 )
else
ps:setColor( 0, 0, 0 )
end
ps:fill()
ps:setColor( 1, 1, 1 )

local xx = 0
local yy = 0
local y = 150

for i = 1, 500 do
yy = y + (amplitude * math.sin( frequency * xx ))
ps:points( xx, yy, 0 )
xx = xx + 1
end

local a_released, f_released
a_released, amplitude = UI.SliderFloat( "Amplitude", amplitude, 0, 150, 500 )
f_released, frequency = UI.SliderFloat( "Frequency", frequency, 0, 0.2, 500 )

UI.Label( "Energy bill increase:" )
UI.ProgressBar( progress_value, 400 )
UI.Button( "Forced height", 0, 200 )
Expand Down
94 changes: 87 additions & 7 deletions ui/ui.lua
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ local ui_scale = 0.0005
local new_scale = nil
local controller_vibrate = false
local image_buttons_default_ttl = 2
local whiteboards_default_ttl = 2
local font = { handle, w, h, scale = 1 }
local caret = { blink_rate = 50, counter = 0 }
local listbox_state = {}
Expand All @@ -49,6 +50,7 @@ local windows = {}
local passes = {}
local textures = {}
local image_buttons = {}
local whiteboards = {}
local color_themes = {}
local window_drag = { id = nil, is_dragging = false, offset = lovr.math.newMat4() }
local layout = { prev_x = 0, prev_y = 0, prev_w = 0, prev_h = 0, row_h = 0, total_w = 0, total_h = 0, same_line = false }
Expand Down Expand Up @@ -175,6 +177,17 @@ local function Clamp( n, n_min, n_max )
return n
end

local function GetLineCount( str )
-- https://stackoverflow.com/questions/24690910/how-to-get-lines-count-in-string/70137660#70137660
local lines = 1
for i = 1, #str do
local c = str:sub( i, i )
if c == '\n' then lines = lines + 1 end
end

return lines
end

local function FindId( t, id )
for i, v in ipairs( t ) do
if v.id == id then
Expand Down Expand Up @@ -400,7 +413,7 @@ local function GenerateOSKTextures()
end

p:plane( m, "fill" )
table.insert(passes, p)
table.insert( passes, p )
end
return passes
end
Expand Down Expand Up @@ -661,8 +674,8 @@ function UI.RenderFrame( main_pass )
end

if theme_changed then
for i, p in ipairs(GenerateOSKTextures()) do
table.insert(passes, p)
for i, p in ipairs( GenerateOSKTextures() ) do
table.insert( passes, p )
end
theme_changed = false
end
Expand All @@ -685,10 +698,22 @@ function UI.RenderFrame( main_pass )
image_buttons[ i ].ttl = image_buttons[ i ].ttl - 1
if image_buttons[ i ].ttl <= 0 then
image_buttons[ i ].texture:release()
image_buttons[ i ].texture = nil
table.remove( image_buttons, i )
end
end
end

if #whiteboards > 0 then
for i = #whiteboards, 1, -1 do
whiteboards[ i ].ttl = whiteboards[ i ].ttl - 1
if whiteboards[ i ].ttl <= 0 then
whiteboards[ i ].texture:release()
whiteboards[ i ].texture = nil
table.remove( whiteboards, i )
end
end
end
end

function UI.SameLine()
Expand Down Expand Up @@ -872,6 +897,59 @@ function UI.ImageButton( img_filename, width, height )
return result
end

function UI.WhiteBoard( name, width, height )
local cur_window = windows[ #windows ]
local my_id = Hash( cur_window.name .. name )
local wb_idx = FindId( whiteboards, my_id )

if wb_idx == nil then
local tex = lovr.graphics.newTexture( width, height, { mipmaps = false } )
local wb = { id = my_id, texture = tex, w = width or tex:getWidth(), h = height or tex:getHeight(), ttl = whiteboards_default_ttl }
table.insert( whiteboards, wb )
wb_idx = #whiteboards
end

local wb = whiteboards[ wb_idx ]
wb.ttl = whiteboards_default_ttl

local bbox = {}
if layout.same_line then
bbox = { x = layout.prev_x + layout.prev_w + margin, y = layout.prev_y, w = wb.w, h = wb.h }
else
bbox = { x = margin, y = layout.prev_y + layout.row_h + margin, w = wb.w, h = wb.h }
end

UpdateLayout( bbox )

local clicked = false
local down = false
local released = false
local hovered = false
if PointInRect( last_off_x, last_off_y, bbox.x, bbox.y, bbox.w, bbox.h ) and cur_window.id == hovered_window_id then
hotID = my_id
hovered = true
if input.trigger == e_trigger.pressed then
activeID = my_id
clicked = true
end
if input.trigger == e_trigger.down and activeID == my_id then
down = true
end
if input.trigger == e_trigger.released and hotID == activeID then
lovr.headset.vibrate( dominant_hand, 0.3, 0.1 )
released = true
end
end

table.insert( windows[ #windows ].command_list, { type = "image", bbox = bbox, texture = wb.texture, color = { 1, 1, 1 } } )

local p = lovr.graphics.getPass( "render", wb.texture )
p:setDepthTest( nil )
p:setProjection( 1, mat4():orthographic( p:getDimensions() ) )
table.insert( passes, p )
return p, clicked, down, released, hovered, last_off_x - bbox.x, last_off_y - bbox.y
end

function UI.Dummy( width, height )
local bbox = {}
if layout.same_line then
Expand Down Expand Up @@ -946,12 +1024,13 @@ function UI.Button( text, width, height )

local text_w = font.handle:getWidth( text )
local text_h = font.handle:getHeight()
local num_lines = GetLineCount( text )

local bbox = {}
if layout.same_line then
bbox = { x = layout.prev_x + layout.prev_w + margin, y = layout.prev_y, w = (2 * margin) + text_w, h = (2 * margin) + text_h }
bbox = { x = layout.prev_x + layout.prev_w + margin, y = layout.prev_y, w = (2 * margin) + text_w, h = (2 * margin) + (num_lines * text_h) }
else
bbox = { x = margin, y = layout.prev_y + layout.row_h + margin, w = (2 * margin) + text_w, h = (2 * margin) + text_h }
bbox = { x = margin, y = layout.prev_y + layout.row_h + margin, w = (2 * margin) + text_w, h = (2 * margin) + (num_lines * text_h) }
end

if width and type( width ) == "number" and width > bbox.w then
Expand Down Expand Up @@ -1391,12 +1470,13 @@ end
function UI.Label( text )
local text_w = font.handle:getWidth( text )
local text_h = font.handle:getHeight()
local num_lines = GetLineCount( text )

local bbox = {}
if layout.same_line then
bbox = { x = layout.prev_x + layout.prev_w + margin, y = layout.prev_y, w = text_w, h = (2 * margin) + text_h }
bbox = { x = layout.prev_x + layout.prev_w + margin, y = layout.prev_y, w = text_w, h = (2 * margin) + (num_lines * text_h) }
else
bbox = { x = margin, y = layout.prev_y + layout.row_h + margin, w = text_w, h = (2 * margin) + text_h }
bbox = { x = margin, y = layout.prev_y + layout.row_h + margin, w = text_w, h = (2 * margin) + (num_lines * text_h) }
end

UpdateLayout( bbox )
Expand Down

0 comments on commit 4a07fd4

Please sign in to comment.