local Nylon = require 'nylon.core'()
local wv = require 'nylon.debug' { name = 'pls-winman' }
local function WindowDim( x, y, w, h )
return { x = x, y = y, w = w, h = h }
end
local function WindowMoveResize( w, dim )
w:resize( dim.h, dim.w )
w:mvwin( dim.y, dim.x )
end
local win_focused
local function entryfn_winman( cord, env )
local tiled = {}
local modal = {}
local landscape = false
local fullscreened = false
local function moveTiledRight_portrait(nexisting)
local halfscreen = math.floor(env.curses.ncols/2)
local h = env.curses.nrows / nexisting
local lasttop = env.curses.nrows
for i = 1, nexisting do
local prev = tiled[i]
local newtop = math.floor(env.curses.nrows-(i*h))
local newdim = WindowDim( halfscreen, newtop, halfscreen, (lasttop-newtop) )
lasttop = newtop
WindowMoveResize( prev.win, newdim )
wv.log('debug','moveTiledRight resized')
prev.on.resized( newdim )
end
end
local function moveTiledRight_landscape(nexisting)
local halfscreen = math.floor(env.curses.nrows/2)
local width = env.curses.ncols / nexisting
local lasttop = env.curses.ncols
for i = 1, nexisting do
local prev = tiled[i]
local newtop = math.floor(env.curses.ncols-(i*width))
local newdim = WindowDim( newtop, halfscreen, (lasttop-newtop), halfscreen )
lasttop = newtop
WindowMoveResize( prev.win, newdim )
wv.log('debug','moveTiledRight resized')
prev.on.resized( newdim )
end
end
local function moveTiledRight(nexisting)
if landscape then
moveTiledRight_landscape(nexisting)
else
moveTiledRight_portrait(nexisting)
end
end
local function resizeAllTiled_portrait()
local top = tiled[#tiled]
local halfscreen = math.floor(env.curses.ncols/2)
local newdim = WindowDim(0,0,halfscreen,env.curses.nrows)
WindowMoveResize( top.win, newdim )
local nexisting = #tiled -1
moveTiledRight(nexisting)
if nexisting > 0 then
moveTiledRight( nexisting )
else
env.curses.screen:clear()
env.curses.screen:refresh()
end
top.on.resized( newdim )
end
local function resizeAllTiled_landscape()
local top = tiled[#tiled]
local halfscreen = math.floor(env.curses.nrows/2)
local newdim = WindowDim(0,0,env.curses.ncols,halfscreen)
WindowMoveResize( top.win, newdim )
local nexisting = #tiled -1
moveTiledRight(nexisting)
if nexisting > 0 then
moveTiledRight( nexisting )
else
env.curses.screen:clear()
env.curses.screen:refresh()
end
top.on.resized( newdim )
end
local function fullscreen_thisWindow( top )
local newdim = WindowDim(0,0,env.curses.ncols,env.curses.nrows)
if top.win then
WindowMoveResize( top.win, newdim )
else
wv.log('debug','weird, window has no window top=%s', top)
end
if top.on and top.on.resized then
top.on.resized( newdim )
else
wv.log('debug','weird, th top=%s', top)
end
end
local d_minimized = WindowDim( 0, 0, 1, 1 )
local function resizeAllTiled()
if not tiled[1] then env.curses.screen:mvaddstr(0,0,"No buffers; press C-l to open or create new record")
env.curses.screen:refresh()
return
end
if #tiled > 1 then
if fullscreened then
fullscreen_thisWindow( fullscreened )
elseif landscape then
resizeAllTiled_landscape()
else
resizeAllTiled_portrait()
end
else fullscreen_thisWindow( tiled[1] )
end
for _, w in ipairs(modal) do
if w.on.resized then
w.on.resized()
end
end
end
local function change_focus(towin)
if win_focused ~= towin then
local prev = win_focused
win_focused = towin
local _ = prev and prev.on.resized and prev.on.resized()
local _ = towin and towin.on.resized and towin.on.resized()
end
end
local function set_best_focus()
change_focus( (#modal > 0) and modal[#modal] or tiled[#tiled] )
end
function cord.event.toggle_landscape()
landscape = not landscape
resizeAllTiled()
end
function cord.event.toggle_fullscreen()
if fullscreened then
fullscreened = false
else
if #tiled > 0 then
fullscreened = tiled[#tiled]
end
end
resizeAllTiled()
end
function cord.event.focused_window_to_primary()
for i, w in ipairs(tiled) do
if w == win_focused then
table.remove(tiled,i)
table.insert(tiled,win_focused)
resizeAllTiled()
return
end
end
end
function cord.event.this_window_to_primary(win)
for i, w in ipairs(tiled) do
if w == win then
table.remove(tiled,i)
table.insert(tiled,win)
resizeAllTiled()
return
end
end
end
function cord.event.other_window()
if #modal > 0 then
wv.log('debug','no window switching when modal dialog is up')
elseif win_focused and #tiled > 1 then
local donext = false
for n = #tiled, 1, -1 do
if donext then
change_focus( tiled[n] )
return
end
donext = (win_focused == tiled[n])
end
change_focus(tiled[#tiled]) end
end
function cord.event.push_tiled( mw )
table.insert( tiled, mw )
resizeAllTiled()
change_focus( mw )
end
function cord.event.remove_tiled( mw )
local remain = {}
for i, v in ipairs(tiled) do
wv.log('debug','winman remove_tiled mw=%s v=%s',mw, v)
if v ~= mw then
table.insert( remain, v )
end
end
tiled = remain
resizeAllTiled()
set_best_focus()
end
function cord.event.Refresh()
resizeAllTiled()
end
function cord.event.swap_tiled()
wv.log('debug','cord.event.swap_tiled #tiled=%d',#tiled)
if #tiled > 1 then
local prevtop = tiled[#tiled]
tiled[#tiled] = tiled[#tiled-1]
tiled[#tiled-1] = prevtop
if fullscreened == prevtop then
fullscreened = tiled[#tiled]
end
resizeAllTiled()
set_best_focus()
end
end
function cord.event.push_modal( mw )
table.insert( modal, mw )
change_focus( mw )
end
function cord.event.remove_modal( mw )
if modal[#modal] ~= mw then
wv.log('error','removed modal dialog not active, fixme')
else
table.remove(modal,#modal)
resizeAllTiled() set_best_focus()
end
end
while true do
cord:sleep(1)
end
end
local Malwin = {}
function Malwin:new( opt )
local o = setmetatable( {}, { __index = self } )
if not opt.win then
wv.log('abnorm','creating winman managed window with no curses window?')
end
o.win = opt.win
o.on = opt.on or {}
return o
end
local function entryfn_key( cord, mainkeyhandler, unhandled_keys )
wv.log '001 entryfn_key'
cord.event.key = function(k)
local mapped = mainkeyhandler(k)
if mapped then if win_focused and win_focused.on.key then
wv.log('norm','input key/map [%s->%s] not handled by main app, passing to focused win',k,mapped)
local rc = win_focused.on.key(mapped)
if rc and unhandled_keys then
unhandled_keys(rc)
end
else
wv.log('abnorm','input key/map [%s->%s] not handled by main app, no focused win with keyhandler',k,mapped)
end
else
wv.log('norm','input key/map [%s] handled by main app',k)
end
end
cord.event.never.wait()
end
local function entryfn_input( cord, cord_key )
wv.log '001 entryfn_input'
Pdcurses.Static.keypad(true);
cord:cthreaded_multi( Pdcurses.Static.cthread_getch_loop(),
function( k )
cord_key.event.key( k )
end )
end
local cord_key
local module = {
win = Malwin,
set_input = function(mainkeyhandler,unhandled_keys)
cord_key = Nylon.cord( 'key', entryfn_key, mainkeyhandler,unhandled_keys )
local cord_input = Nylon.cord( 'input', entryfn_input, cord_key )
end,
inject_key = function(k)
cord_key.event.key(k)
end
}
local function malwin_cleanup(malwin)
if not malwin.win then
wv.log('abnorm','removing win twice')
else
malwin.win:clear()
malwin.win:refresh()
malwin.win:forcedelete()
malwin.win = nil
end
end
function module.create( env )
local cord_winman = Nylon.cord( 'winman', entryfn_winman, env )
function module.push(malwin)
cord_winman.event.push_tiled(malwin)
return function()
wv.log('debug','remove pushed win=%s',malwin)
cord_winman.event.remove_tiled(malwin)
malwin_cleanup(malwin)
end
end
function module.swap_tiled()
wv.log('debug','Winman.swap_tiled fn')
cord_winman.event.swap_tiled()
end
function module.remove_focused()
cord_winman.event.remove_focused()
end
function module.push_modal(malwin)
cord_winman.event.push_modal( malwin )
return function()
wv.log('debug','remove modal win=%s',malwin)
cord_winman.event.remove_modal(malwin)
malwin_cleanup( malwin )
end
end
function module.other_window()
cord_winman.event.other_window()
end
function module.toggle_landscape()
cord_winman.event.toggle_landscape()
end
function module.toggle_fullscreen()
cord_winman.event.toggle_fullscreen()
end
function module.isFocused(w)
return w == win_focused
end
function module.Refresh()
cord_winman.event.Refresh()
end
function module.focused_window_to_primary()
cord_winman.event.focused_window_to_primary()
end
function module.this_window_to_primary(win)
cord_winman.event.this_window_to_primary(win)
end
end
return module