import CreateWindow , { Window , paddingX } from '../windows/window' ; import { cursor , moveCursor } from '../cursor' ; import CreateWebGLRenderer from '../render/webgl/renderer' ; import { onElementResize } from '../ui/vanilla' ; import * as workspace from '../workspace' ; import { throttle } from '../../common/utils' ; import windowSizer from '../windows/sizer' ; import { Events } from '../../common/ipc' ; export const size = { width : 0 , height : 0 } ; export const webgl = CreateWebGLRenderer ( ) ; const windowsByGrid = new Map < number , Window > ( ) ; const windowsById = new Map < number , Window > ( ) ; const invalidGrids = new Set < number > ( ) ; let activeGrid = 0 ; const container = document . getElementById ( 'windows' ) as HTMLElement ; const webglContainer = document . getElementById ( 'webgl' ) as HTMLElement ; const getWindowById = ( windowId ) => { const win = windowsById . get ( windowId ) ; if ( ! win ) throw new Error ( `trying to get window that does not exist ${ windowId }` ) ; return win ; } ; export const refreshWebGLGrid = ( ) => { webgl . clearAll ( ) ; windowsByGrid . forEach ( ( w ) => w . redrawFromGridBuffer ( ) ) ; } ; webgl . canvasElement . addEventListener ( 'webglcontextlost' , ( e ) => { console . log ( 'lost webgl context, preventing default' , e ) ; e . preventDefault ( ) ; } ) ; webgl . canvasElement . addEventListener ( 'webglcontextrestored' , ( _e ) => { console . log ( 'webgl context restored! re-initializing' ) ; webgl . reInit ( ) ; refreshWebGLGrid ( ) ; } ) ; export const calculateGlobalOffset = ( anchorWin , float ) => { if ( ! anchorWin . element . style . gridArea ) throw new Error ( "Anchor doesn't have grid-area css" ) ; if ( ! float . element . style . top ) throw new Error ( "Floating window doesn't have top positioning" ) ; if ( ! float . element . style . left ) throw new Error ( "Floating window doesn't have left positioning" ) ; const [ rowStart , colStart ] = anchorWin . element . style . gridArea . split ( '/' ) ; const nTop = parseInt ( rowStart , 10 ) ; const nLeft = parseInt ( colStart , 10 ) ; if ( nTop > 1 ) { Object . assign ( float . element . style , { top : parseInt ( float . element . style . top , 10 ) + workspace . size . nameplateHeight + 'px' , } ) ; } if ( nLeft > 1 ) { Object . assign ( float . element . style , { left : parseInt ( float . element . style . left , 10 ) + workspace . pad . x + paddingX + 'px' , } ) ; } } ; export const createWebGLView = ( gridId ) => webgl . createView ( gridId ) ; export const getActiveGridId = ( ) => activeGrid ; export const setActiveGrid = ( id ) => ( activeGrid = id ) ; export const getActive = ( ) => { const win = windowsByGrid . get ( activeGrid ) ; if ( ! win ) throw new Error ( `trying to get window that does not exist ${ activeGrid }` ) ; return win ; } ; export const set = ( winId , gridId , row , col , width , height , is_float = false , anchor = '' ) => { const win = windowsByGrid . get ( gridId ) || CreateWindow ( ) ; win . setWindowInfo ( { anchor , is_float , row , col , width , height , visible : true , id : winId , gridId : gridId , } ) ; if ( ! windowsByGrid . has ( gridId ) ) windowsByGrid . set ( gridId , win ) ; if ( ! windowsById . has ( winId ) ) windowsById . set ( winId , win ) ; if ( winId < 0 ) return invalidGrids . add ( gridId ) ; container . appendChild ( win . element ) ; invalidGrids . delete ( gridId ) ; } ; export const disposeInvalidWindows = ( ) => { invalidGrids . forEach ( ( gid ) => { const win = windowsByGrid . get ( gid ) ; if ( ! win ) throw new Error ( `window grid does not exist ${ gid }` ) ; windowsByGrid . delete ( gid ) ; windowsById . delete ( win . id ) ; invalidGrids . delete ( gid ) ; } ) ; invalidGrids . delete ( - 1 ) ; } ; export const remove = ( gridId ) => { const win = windowsByGrid . get ( gridId ) ; if ( ! win ) return console . warn ( `trying to destroy a window that does not exist ${ gridId }` ) ; requestAnimationFrame ( ( ) => { win . element . remove ( ) ; windowsById . delete ( win . getWindowInfo ( ) . id ) ; windowsByGrid . delete ( gridId ) ; } ) ; } ; export const get = ( gridId ) => { const win = windowsByGrid . get ( gridId ) ; if ( ! win ) throw new Error ( `trying to get window that does not exist ${ gridId }` ) ; return win ; } ; export const has = ( gridId ) => windowsByGrid . has ( gridId ) ; export const layout = ( ) => { const wininfos = [ ] ; for ( const [ _ , win ] of windowsByGrid ) { wininfos . push ( win . getWindowInfo ( ) ) ; } const { gridTemplateRows , gridTemplateColumns , windowGridInfo } = windowSizer ( wininfos ) ; Object . assign ( container . style , { gridTemplateRows , gridTemplateColumns } ) ; windowGridInfo . forEach ( ( { gridId , gridRow , gridColumn } ) => { windowsByGrid . get ( gridId ) ! . applyGridStyle ( { gridRow , gridColumn } ) ; } ) ; windowGridInfo . forEach ( ( { gridId } ) => windowsByGrid . get ( gridId ) ! . refreshLayout ( ) ) ; refreshWebGLGrid ( ) ; activeGrid && requestAnimationFrame ( ( ) => { if ( ! windowsByGrid . has ( activeGrid ) ) return ; moveCursor ( cursor . row , cursor . col ) ; } ) ; } ; const updateWindowNameplates = ( ) => requestAnimationFrame ( async ( ) => { const windowsWithMetadata = await window . api . getWindowMetadata ( ) ; windowsWithMetadata . forEach ( ( w ) => getWindowById ( w . id ) . updateNameplate ( w ) ) ; } ) ; export const refresh = throttle ( updateWindowNameplates , 5 ) ; export const hide = ( gridIds ) => gridIds . forEach ( ( [ gridId ] ) => get ( gridId ) . hide ( ) ) ; export const pixelPosition = ( row , col ) => { const win = windowsByGrid . get ( activeGrid ) ; if ( win ) return win . positionToWorkspacePixels ( row , col ) ; console . warn ( 'no active window grid... hmmm *twisty effect*' ) ; return { x : 0 , y : 0 } ; } ; webgl . canvasElement . setAttribute ( 'wat' , 'webgl-background' ) ; Object . assign ( webglContainer . style , { position : 'absolute' , width : '100%' , height : '100%' , flex : 1 , zIndex : 2 , background : 'var(--background)' , } ) ; Object . assign ( container . style , { position : 'absolute' , width : '100%' , height : '100%' , flex : 1 , zIndex : 5 , display : 'grid' , justifyItems : 'stretch' , alignItems : 'stretch' , background : 'none' , } ) ; webglContainer . appendChild ( webgl . canvasElement ) ; onElementResize ( webglContainer , ( w , h ) => { Object . assign ( size , { width : w , height : h } ) ; webgl . resizeCanvas ( w , h ) ; for ( const [ _ , win ] of windowsByGrid ) { win . refreshLayout ( ) ; win . redrawFromGridBuffer ( ) ; } } ) ; window . api . on ( Events . colorschemeStateUpdated , ( ) => requestAnimationFrame ( ( ) => { webgl . clearAll ( ) ; for ( const [ _ , win ] of windowsByGrid ) { win . redrawFromGridBuffer ( ) ; } } ) ) ; export const resetAtlasBounds = ( ) => { for ( const [ _ , win ] of windowsByGrid ) { win . webgl . resetAtlasBounds ( ) ; } } ;