2022-09-03 21:54:38 +01:00
utf8 = require ' utf8 '
2022-10-30 00:43:13 +01:00
json = require ' json '
2022-05-02 16:20:30 +01:00
2022-10-30 00:43:13 +01:00
require ' app '
require ' test '
2022-11-27 22:06:11 +00:00
require ' live '
2022-07-12 21:45:38 +01:00
2022-10-30 00:43:13 +01:00
require ' keychord '
require ' button '
2022-08-24 21:27:04 +01:00
2022-10-30 00:43:13 +01:00
-- delegate most business logic to a layer that can be reused by other projects
require ' edit '
Editor_state = { }
2022-06-07 21:35:56 +01:00
2023-04-20 03:45:17 +01:00
function App . version_check ( )
2023-04-20 08:30:25 +01:00
-- available modes: run, error
Mode = ' run '
Error_message = nil
Error_count = 0
-- we'll reuse error mode on load for an initial version check
2023-04-20 03:45:17 +01:00
Supported_versions = { ' 11.4 ' , ' 11.3 ' , ' 11.2 ' , ' 11.1 ' , ' 11.0 ' } -- keep these sorted in descending order
local major , minor = love.getVersion ( )
Version = major .. ' . ' .. minor
2023-04-20 08:30:25 +01:00
if array.find ( Supported_versions , Version ) == nil then
Mode = ' error '
Error_message = ( " This app doesn't support version %s; please use version %s. Press any key to try it with this version anyway. " ) : format ( Version , Supported_versions [ 1 ] )
print ( Error_message )
-- continue initializing everything; hopefully we won't have errors during initialization
2023-04-20 03:45:17 +01:00
end
end
2022-10-30 00:43:13 +01:00
-- called both in tests and real run
function App . initialize_globals ( )
-- tests currently mostly clear their own state
2022-06-09 16:15:32 +01:00
2022-10-30 00:43:13 +01:00
-- blinking cursor
Cursor_time = 0
2022-07-01 06:46:45 +01:00
2022-09-03 21:54:38 +01:00
-- for hysteresis in a few places
2022-11-04 04:02:31 +00:00
Current_time = 0
Last_focus_time = 0 -- https://love2d.org/forums/viewtopic.php?p=249700
Last_resize_time = 0
2022-07-01 06:46:45 +01:00
end
2022-05-02 05:55:57 +01:00
2022-10-30 00:43:13 +01:00
-- called only for real run
2022-09-03 21:54:38 +01:00
function App . initialize ( arg )
2022-10-30 00:43:13 +01:00
love.keyboard . setTextInput ( true ) -- bring up keyboard on touch screen
love.keyboard . setKeyRepeat ( true )
2022-06-07 21:24:43 +01:00
2022-11-27 22:06:11 +00:00
Editor_state = nil -- not used outside editor tests
2022-10-30 00:43:13 +01:00
love.graphics . setBackgroundColor ( 1 , 1 , 1 )
2022-11-27 22:06:11 +00:00
live.initialize ( arg )
2022-10-30 00:43:13 +01:00
if love.filesystem . getInfo ( ' config ' ) then
load_settings ( )
2022-09-03 21:54:38 +01:00
else
2022-10-30 00:43:13 +01:00
initialize_default_settings ( )
2022-09-03 21:54:38 +01:00
end
2022-06-07 21:19:17 +01:00
2023-03-25 18:41:52 +00:00
2023-06-19 06:44:27 +01:00
-- TODO: app-specific stuff goes here
2023-03-25 18:41:52 +00:00
-- keep a few blank lines around: https://merveilles.town/@akkartik/110084833821965708
2022-11-27 19:05:14 +00:00
love.window . setTitle ( ' TODO ' )
2022-10-30 00:43:13 +01:00
2023-03-25 18:41:52 +00:00
2022-11-27 22:54:48 +00:00
if on.initialize then on.initialize ( arg ) end
2022-10-30 00:43:13 +01:00
if rawget ( _G , ' jit ' ) then
jit.off ( )
jit.flush ( )
2022-09-03 21:54:38 +01:00
end
2022-05-16 23:26:22 +01:00
end
2023-06-04 23:25:46 +01:00
function print_and_log ( s )
print ( s )
log ( 3 , s )
end
2023-01-02 01:52:06 +00:00
function love . quit ( )
if on.quit then on.quit ( ) end
2023-01-02 02:19:08 +00:00
love.filesystem . write ( ' config ' , json.encode ( settings ( ) ) )
end
2023-04-08 02:18:43 +01:00
function restart ( )
if on.quit then on.quit ( ) end
love.filesystem . write ( ' config ' , json.encode ( settings ( ) ) )
load_settings ( )
if on.initialize then on.initialize ( ) end
end
2023-01-02 02:19:08 +00:00
function settings ( )
local x , y , displayindex = App.screen . position ( )
return {
x = x , y = y , displayindex = displayindex ,
width = App.screen . width , height = App.screen . height ,
2023-01-02 02:22:52 +00:00
app = on.save_settings and on.save_settings ( ) ,
2023-01-02 02:19:08 +00:00
}
2023-01-02 01:52:06 +00:00
end
2023-01-02 01:50:41 +00:00
function load_settings ( )
2022-10-30 00:43:13 +01:00
local settings = json.decode ( love.filesystem . read ( ' config ' ) )
2023-07-11 02:41:23 +01:00
_ , _ , App.screen . flags = App.screen . size ( )
2022-10-30 00:43:13 +01:00
App.screen . flags.resizable = true
App.screen . width , App.screen . height = settings.width , settings.height
2023-03-19 07:04:53 +00:00
App.screen . resize ( App.screen . width , App.screen . height , App.screen . flags )
2023-07-11 02:41:23 +01:00
set_window_position_from_settings ( settings )
2023-07-11 03:07:02 +01:00
if on.load_settings then on.load_settings ( settings.app ) end
2022-10-30 00:43:13 +01:00
end
2023-07-11 02:41:23 +01:00
function set_window_position_from_settings ( settings )
local os = love.system . getOS ( )
if os == ' Linux ' then
-- love.window.setPosition doesn't quite seem to do what is asked of it on Linux.
App.screen . move ( settings.x , settings.y - 37 , settings.displayindex )
2023-01-02 01:51:35 +00:00
else
2023-07-11 02:41:23 +01:00
App.screen . move ( settings.x , settings.y , settings.displayindex )
2023-01-02 01:51:35 +00:00
end
2022-10-30 00:43:13 +01:00
end
function initialize_default_settings ( )
local font_height = 20
love.graphics . setFont ( love.graphics . newFont ( font_height ) )
2023-08-05 08:08:02 +01:00
initialize_window_geometry ( )
2022-10-30 00:43:13 +01:00
end
2023-07-11 19:11:48 +01:00
function initialize_window_geometry ( )
2023-07-11 02:41:23 +01:00
-- Initialize window width/height and make window resizable.
--
-- I get tempted to have opinions about window dimensions here, but they're
-- non-portable:
-- - maximizing doesn't work on mobile and messes things up
-- - maximizing keeps the title bar on screen in Linux, but off screen on
-- Windows. And there's no way to get the height of the title bar.
-- It seems more robust to just follow LÖVE's default window size until
-- someone overrides it.
2023-03-19 07:04:53 +00:00
App.screen . width , App.screen . height , App.screen . flags = App.screen . size ( )
2022-10-30 00:43:13 +01:00
App.screen . flags.resizable = true
2023-03-19 07:04:53 +00:00
App.screen . resize ( App.screen . width , App.screen . height , App.screen . flags )
2022-10-30 00:43:13 +01:00
end
function App . resize ( w , h )
--? print(("Window resized to width: %d and height: %d."):format(w, h))
App.screen . width , App.screen . height = w , h
2022-11-04 04:46:20 +00:00
Last_resize_time = Current_time
2022-11-27 22:06:11 +00:00
if on.resize then on.resize ( w , h ) end
2022-10-30 00:43:13 +01:00
end
function App . filedropped ( file )
2023-01-20 22:18:04 +00:00
if on.file_drop then on.file_drop ( file ) end
2022-10-30 00:43:13 +01:00
end
2022-05-23 02:27:48 +01:00
function App . draw ( )
2023-04-20 08:30:25 +01:00
if Mode == ' error ' then
love.graphics . setColor ( 0 , 0 , 1 )
love.graphics . rectangle ( ' fill ' , 0 , 0 , App.screen . width , App.screen . height )
love.graphics . setColor ( 1 , 1 , 1 )
love.graphics . printf ( Error_message , 40 , 40 , 600 )
2023-04-20 03:45:17 +01:00
return
end
2022-11-27 22:06:11 +00:00
if on.draw then on.draw ( ) end
2022-05-02 05:55:57 +01:00
end
2022-05-23 02:27:48 +01:00
function App . update ( dt )
2022-11-04 04:02:31 +00:00
Current_time = Current_time + dt
2022-07-12 21:45:38 +01:00
-- some hysteresis while resizing
2022-11-04 04:02:31 +00:00
if Current_time < Last_resize_time + 0.1 then
2022-07-25 23:23:01 +01:00
return
2022-07-12 21:45:38 +01:00
end
2022-10-30 00:43:13 +01:00
Cursor_time = Cursor_time + dt
2023-04-20 08:30:25 +01:00
-- listen for commands in both 'error' and 'run' modes
2022-11-27 22:27:04 +00:00
live.update ( dt )
2023-04-20 08:30:25 +01:00
if Mode == ' run ' then
if on.update then on.update ( dt ) end
end
2022-10-30 00:43:13 +01:00
end
function App . mousepressed ( x , y , mouse_button )
2023-04-20 08:30:25 +01:00
if Mode == ' error ' then return end
2022-10-30 00:43:13 +01:00
Cursor_time = 0 -- ensure cursor is visible immediately after it moves
2022-12-24 04:30:35 +00:00
if on.mouse_press then on.mouse_press ( x , y , mouse_button ) end
2022-10-30 00:43:13 +01:00
end
function App . mousereleased ( x , y , mouse_button )
2023-04-20 08:30:25 +01:00
if Mode == ' error ' then return end
2022-10-30 00:43:13 +01:00
Cursor_time = 0 -- ensure cursor is visible immediately after it moves
2022-12-24 04:30:35 +00:00
if on.mouse_release then on.mouse_release ( x , y , mouse_button ) end
2022-10-30 00:43:13 +01:00
end
2023-03-24 04:48:27 +00:00
function App . wheelmoved ( dx , dy )
2023-04-20 08:30:25 +01:00
if Mode == ' error ' then return end
2023-03-24 04:48:27 +00:00
Cursor_time = 0 -- ensure cursor is visible immediately after it moves
2023-03-24 04:48:42 +00:00
if on.mouse_wheel_move then on.mouse_wheel_move ( dx , dy ) end
2023-03-24 04:48:27 +00:00
end
2022-10-30 00:43:13 +01:00
function App . focus ( in_focus )
2023-04-20 08:30:25 +01:00
if Mode == ' error ' then return end
2022-10-30 00:43:13 +01:00
if in_focus then
2022-11-04 04:46:20 +00:00
Last_focus_time = Current_time
2022-09-03 21:54:38 +01:00
end
2022-12-17 16:49:45 +00:00
if in_focus then
love.graphics . setBackgroundColor ( 1 , 1 , 1 )
else
2023-01-02 01:52:51 +00:00
love.graphics . setBackgroundColor ( 0.8 , 0.8 , 0.8 )
2022-12-17 16:49:45 +00:00
end
2022-11-27 22:06:11 +00:00
if on.focus then on.focus ( in_focus ) end
2022-05-14 21:08:33 +01:00
end
2022-11-27 22:06:11 +00:00
-- App.keypressed is defined in keychord.lua
2022-12-24 01:16:19 +00:00
function App . keychord_press ( chord , key )
2023-04-20 08:30:25 +01:00
if Mode == ' error ' then
if chord == ' C-c ' then
love.system . setClipboardText ( Error_message )
end
return
end
2022-09-03 21:54:38 +01:00
-- ignore events for some time after window in focus (mostly alt-tab)
2022-11-04 04:02:31 +00:00
if Current_time < Last_focus_time + 0.01 then
2022-09-03 21:54:38 +01:00
return
end
2022-10-30 00:43:13 +01:00
Cursor_time = 0 -- ensure cursor is visible immediately after it moves
2022-12-24 04:17:16 +00:00
if on.keychord_press then on.keychord_press ( chord , key ) end
2022-07-25 23:33:06 +01:00
end
2022-05-23 02:27:48 +01:00
function App . textinput ( t )
2023-04-20 08:30:25 +01:00
if Mode == ' error ' then return end
2022-09-03 21:54:38 +01:00
-- ignore events for some time after window in focus (mostly alt-tab)
2022-11-04 04:02:31 +00:00
if Current_time < Last_focus_time + 0.01 then
2022-07-25 23:33:06 +01:00
return
end
2022-10-30 00:43:13 +01:00
Cursor_time = 0 -- ensure cursor is visible immediately after it moves
2022-12-24 04:17:16 +00:00
if on.text_input then on.text_input ( t ) end
2022-05-21 22:03:06 +01:00
end
2022-10-30 00:43:13 +01:00
function App . keyreleased ( key , scancode )
2023-04-20 08:30:25 +01:00
if Mode == ' error ' then
2023-04-20 03:45:17 +01:00
Mode = ' run '
return
end
2022-09-03 21:54:38 +01:00
-- ignore events for some time after window in focus (mostly alt-tab)
2022-11-04 04:02:31 +00:00
if Current_time < Last_focus_time + 0.01 then
2022-07-25 23:33:06 +01:00
return
end
2022-10-30 00:43:13 +01:00
Cursor_time = 0 -- ensure cursor is visible immediately after it moves
2023-01-17 06:46:40 +00:00
if on.key_release then on.key_release ( key , scancode ) end
2022-05-02 16:20:30 +01:00
end