first draft of load/save buttons

Some considerations in the design so far:
* Desired flows:
  * start typing into a new pane, then save to a filename
  * load from a filename, then continue typing/running
  * save as a second file

* Should we autosave? I think not yet, because my editor's undo/redo
  functionality is not accessible yet on mobile. Android devices can't
  press 'ctrl', and the hotkeys aren't very discoverable.

  (I considered menu options for 'undo' and 'redo', but they won't be
  very ergonomic because my undo/redo functionality is primitive and
  doesn't support grouping similar operations. Now you're stuck tapping
  '>>', then 'undo' and losing one character. Then the menu closes and
  you have to do it all over again.)

  Another knock against autosave on mobile: autosave on quit is
  unreliable. At least on my Android devices, LÖVE doesn't trigger
  love.quit when you swipe away an app. iOS of course has no such notion
  in the first place.

* Menu buttons take up space, and I'm loath to expend 2 more buttons.
  However, I don't see a good alternative:

  * We can't use a single button to bind a filename to a pane until we
    get autosave.

  * Save on run? It doesn't save a button, but maybe we can keep 'save'
    up top because we'll want to keep hitting it in the absence of
    autosave. However, I don't want to lose data just because I started
    typing out a long program that never got to a runnable point.

* I'd like to keep 'save' always up. But newcomers might have more
  trouble finding things if load and save are separated from each other.
  Seems like the sort of thing Mike complained about before the current
  button organization.

==> conclusion: no autosave, 2 buttons, load and save

* I want to follow MiniIDE and only save to a single directory (no
  subdirectories, even). Simplifies the file dialog.

* Where should this directory live? Source base risks growing really
  large and unwieldy over time as we share files between lots of LÖVE
  apps. At least, Mike has that problem. Save dir is utterly
  inaccessible to other apps -- including later versions of this one.
  Once you delete one version of an app (say before installing a new
  version) the only way to find your files is to wade through lots of
  cryptic directories inside source dir. And you'd need a new LÖVE app
  to do that.

==> conclusion: save to a fixed subdir of source base dir. That way only
Lua Carousel will save there, but different versions share a common
space.

* Should examples be savable? If yes, we could have conflicts. If no,
  it feels like a gotcha when someone starts editing an example.

==> conclusion: allow examples to be saved, but that creates a new copy
of them on restart. It'll be weird that the order changes, but seems
like the best option.

* Where to show the current filename? I don't want to further reduce
  space for buttons. A smaller font seems necessary here to squeeze the
  filename into an interstitial of the UI.

Still to do: providing a non-existing file to load/save. I plan a
command palette UI for filtering or selecting a new file.
This commit is contained in:
Kartik K. Agaram 2023-11-25 23:15:05 -08:00
parent 54ef90bca7
commit 83ebcaa5c4
16 changed files with 119 additions and 2 deletions

View File

@ -1,4 +1,5 @@
on.initialize = function()
App.mkdir(Directory)
populate_missing_handlers()
love.graphics.setFont(love.graphics.newFont(Font_height))
Line_height = math.floor(Font_height*1.3)

View File

@ -1,5 +1,10 @@
on.draw = function()
Global_state.button_handlers = {}
-- modal dialog
if Show_file_dialog then
draw_file_dialog()
return
end
Overflow_button = nil
love.graphics.setBackgroundColor(Background_color.r, Background_color.g, Background_color.b)
draw_canvas()

View File

@ -1,4 +1,8 @@
on.keychord_press = function(chord, key)
if Show_file_dialog then
Show_file_dialog = false
return
end
if chord == 'C-=' then
update_font_settings(Current_pane.editor_state.font_height+2)
elseif chord == 'C--' then

View File

@ -1,11 +1,26 @@
draw_editor_border = function()
App.color(Normal_color)
App.color{r=0.5, g=0.5, b=0.5}
local x1 = Current_pane.editor_state.left-5-Line_number_padding
local y1 = Current_pane.editor_state.top-5
local x2 = Current_pane.editor_state.right+5
local y2 = Current_pane.editor_state.bottom+5
-- upper border
love.graphics.line(x1,y1, x2,y1)
if Current_pane.filename then
-- title in between if it exists
local old_font = love.graphics.getFont()
if Title_font == nil then
Title_font = love.graphics.newFont(15) -- 20 pixels between menu and upper border - 5
end
love.graphics.setFont(Title_font)
local tx1 = Current_pane.editor_state.left
local tx2 = tx1 + App.width(Current_pane.filename)
love.graphics.print(Current_pane.filename, tx1, y1-15+5)
love.graphics.setFont(old_font)
love.graphics.line(x1,y1, tx1-5,y1)
love.graphics.line(math.min(tx2+5,x2), y1, x2,y1)
else
love.graphics.line(x1,y1, x2,y1)
end
love.graphics.line(x1,y1, x1,y1+10)
love.graphics.line(x2,y1, x2,y1+10)
-- lower border

View File

@ -28,6 +28,8 @@ draw_menu = function()
else
x, y = show_code_button(x, y, r)
end
x, y = save_button(x, y, r)
x, y = load_button(x, y, r)
x, y = copy_button(x, y, r)
x, y = paste_button(x, y, r)
x, y = clear_pane_button(x, y, r)

2
0115-Title_font Normal file
View File

@ -0,0 +1,2 @@
-- Lua Carousel is almost entirely in a single (adjustable) font, but we make one exception to squeeze in a file name
Title_font = nil

16
0116-save_button Normal file
View File

@ -0,0 +1,16 @@
save_button = function(x, y, r)
return overflowable_button('save', x, y, r,
function()
print('save')
if Current_pane.filename == nil then
Directory_contents = nil -- refresh from file system
Show_file_dialog = true
File_dialog_callback = function(filename)
Current_pane.filename = filename
one_time_save()
end
else
one_time_save()
end
end)
end

11
0117-load_button Normal file
View File

@ -0,0 +1,11 @@
load_button = function(x, y, r)
return overflowable_button('load', x, y, r,
function()
Directory_contents = nil -- refresh from file system
Show_file_dialog = true
File_dialog_callback = function(filename)
Current_pane.filename = filename
one_time_load()
end
end)
end

30
0119-draw_file_dialog Normal file
View File

@ -0,0 +1,30 @@
draw_file_dialog = function()
App.color(Menu_background)
love.graphics.rectangle('fill',
Menu_left+5,
Menu_bottom+5,
Safe_width-Menu_left-10,
Safe_height-Menu_bottom-10)
if Directory_contents == nil then
-- on the first frame after dialog is enabled
refresh_directory_contents()
end
local x, y = Menu_left+10, Menu_bottom+10
for _,filename in ipairs(Directory_contents) do
local w = App.width(filename) + 10
if x == Menu_left+10 or x+w < Safe_width-Menu_left-10 then
styled_button(filename, x,y, function()
File_dialog_callback(filename)
Show_file_dialog = false
File_dialog_callback = nil
end)
x = x+w+10
else
x = Menu_left+10
y = y+Line_height+10
if y > Safe_height-Menu_bottom-10 then
break
end
end
end
end

1
0120-Show_file_dialog Normal file
View File

@ -0,0 +1 @@
Show_file_dialog = false

1
0121-Directory Normal file
View File

@ -0,0 +1 @@
Directory = love.filesystem.getSourceBaseDirectory()..'/carousel_data/'

2
0122-Directory_contents Normal file
View File

@ -0,0 +1,2 @@
-- filenames inside directory
Directory_contents = nil

View File

@ -0,0 +1,10 @@
refresh_directory_contents = function()
Directory_contents = {}
local files_info = nativefs.getDirectoryItemsInfo(Directory)
for _,file_info in ipairs(files_info) do
if file_info.type == 'file' then
table.insert(Directory_contents, file_info.name)
end
end
table.sort(Directory_contents)
end

View File

@ -0,0 +1,2 @@
-- Function that is called when a 'filename' is selected from the file dialog, e.g. to load from or save to a file.
File_dialog_callback = nil

7
0126-one_time_save Normal file
View File

@ -0,0 +1,7 @@
one_time_save = function()
print('saving to '..Current_pane.filename)
Current_pane.editor_state.filename = Directory..Current_pane.filename
save_to_disk(Current_pane.editor_state)
-- Don't autosave yet; undo isn't accessible in mobile devices.
Current_pane.editor_state.filename = nil
end

8
0127-one_time_load Normal file
View File

@ -0,0 +1,8 @@
one_time_load = function()
print('loading '..Current_pane.filename)
Current_pane.editor_state.filename = Directory..Current_pane.filename
load_from_disk(Current_pane.editor_state)
Text.redraw_all(Current_pane.editor_state)
-- Disable autosave; undo isn't accessible in mobile devices.
Current_pane.editor_state.filename = nil
end