window.monkey2 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655
  1. Namespace mojo.app
  2. #rem monkeydoc Window creation flags.
  3. | WindowFlags | Description
  4. |:--------------|:-----------
  5. | CenterX | Center window horizontally.
  6. | CenterY | Center window vertically.
  7. | Center | Center window.
  8. | Hidden | Window is initally hidden.
  9. | Resizable | Window is resizable.
  10. | Fullscreen | Window is a fullscreen window.
  11. | Maximized | Window is maximized.
  12. | Minimized | Window is minimized.
  13. #end
  14. Enum WindowFlags
  15. CenterX=1
  16. CenterY=2
  17. Hidden=4
  18. Resizable=8
  19. Borderless=16
  20. Fullscreen=32
  21. HighDPI=64
  22. Maximized=128
  23. Minimized=256
  24. Center=CenterX|CenterY
  25. End
  26. #rem monkeydoc The Window class.
  27. #end
  28. Class Window Extends View
  29. #rem monkeydoc Creates a new window.
  30. #end
  31. Method New( title:String="Window",width:Int=640,height:Int=480,flags:WindowFlags=Null )
  32. Init( title,New Recti( 0,0,width,height ),flags|WindowFlags.Center )
  33. End
  34. Method New( title:String,rect:Recti,flags:WindowFlags=Null )
  35. Init( title,rect,flags )
  36. End
  37. #rem monkeydoc The window title text.
  38. #end
  39. Property Title:String()
  40. Return String.FromCString( SDL_GetWindowTitle( _sdlWindow ) )
  41. Setter( title:String )
  42. SDL_SetWindowTitle( _sdlWindow,title )
  43. End
  44. #rem monkeydoc The window clear color.
  45. #end
  46. Property ClearColor:Color()
  47. Return _clearColor
  48. Setter( clearColor:Color )
  49. _clearColor=clearColor
  50. End
  51. #rem monkeydoc True if window clearing is enabled.
  52. #end
  53. Property ClearEnabled:Bool()
  54. Return _clearEnabled
  55. Setter( clearEnabled:Bool )
  56. _clearEnabled=clearEnabled
  57. End
  58. #rem monkeydoc The window swap interval.
  59. #end
  60. Property SwapInterval:Int()
  61. Return _swapInterval
  62. Setter( swapInterval:Int )
  63. _swapInterval=swapInterval
  64. End
  65. #rem monkeydoc Window fullscreen state.
  66. Note: The setter for this property deprecated! Please use BeginFullscreen/EndFullscreen instead.
  67. #end
  68. Property Fullscreen:Bool()
  69. Return Cast<SDL_WindowFlags>( SDL_GetWindowFlags( _sdlWindow ) ) & SDL_WINDOW_FULLSCREEN
  70. Setter( fullscreen:Bool )
  71. If fullscreen=Fullscreen Return
  72. If fullscreen BeginFullscreen() Else EndFullscreen()
  73. End
  74. #rem monkeydoc Window maximized state.
  75. #end
  76. Property Maximized:Bool()
  77. Return Cast<SDL_WindowFlags>( SDL_GetWindowFlags( _sdlWindow ) ) & SDL_WINDOW_MAXIMIZED
  78. End
  79. #rem monkeydoc Window minimized state.
  80. #end
  81. Property Minimized:Bool()
  82. Return Cast<SDL_WindowFlags>( SDL_GetWindowFlags( _sdlWindow ) ) & SDL_WINDOW_MINIMIZED
  83. End
  84. #rem monkeydoc Window content view.
  85. During layout, the window's content view is resized to fill the window.
  86. #end
  87. Property ContentView:View()
  88. Return _contentView
  89. Setter( contentView:View )
  90. If _contentView RemoveChildView( _contentView )
  91. _contentView=contentView
  92. If _contentView AddChildView( _contentView )
  93. End
  94. #rem monkeydoc Switches to 'desktop' fullscreen mode.
  95. Switches to 'desktop' fullscreen mode.
  96. The window is resized to cover the entire desktop and any window decorations are hidden.
  97. The display resolution does not actually change.
  98. #end
  99. Method BeginFullscreen()
  100. SDL_SetWindowFullscreen( _sdlWindow,SDL_WINDOW_FULLSCREEN_DESKTOP )
  101. End
  102. #rem monkeydoc Changes display mode and switches to fullscreen mode.
  103. The display resolution is changed, the window is resized and any window decorations are hidden.
  104. #end
  105. Method BeginFullscreen( width:Int,height:Int,hertz:Int )
  106. Local mode:SDL_DisplayMode
  107. mode.w=width
  108. mode.h=height
  109. mode.refresh_rate=hertz
  110. Local closest:SDL_DisplayMode
  111. SDL_GetClosestDisplayMode( 0,Varptr mode,Varptr closest )
  112. SDL_SetWindowDisplayMode( _sdlWindow,Varptr closest )
  113. SDL_SetWindowFullscreen( _sdlWindow,SDL_WINDOW_FULLSCREEN )
  114. End
  115. #rem monkeydoc Ends fullscreen mode.
  116. #end
  117. Method EndFullscreen()
  118. SDL_SetWindowFullscreen( _sdlWindow,0 )
  119. End
  120. #rem monkeydoc Maximizes the window.
  121. #end
  122. Method Maximize()
  123. SDL_MaximizeWindow( _sdlWindow )
  124. End
  125. #rem monkeydoc Minimizes the window.
  126. #end
  127. Method Minimize()
  128. SDL_MinimizeWindow( _sdlWindow )
  129. End
  130. #rem monkeydoc Restores the window.
  131. #end
  132. Method Restore()
  133. SDL_RestoreWindow( _sdlWindow )
  134. End
  135. '***** INTERNAL *****
  136. #rem monkeydoc @hidden
  137. #End
  138. Method UpdateWindow( render:Bool )
  139. LayoutWindow()
  140. If render RenderWindow()
  141. End
  142. #rem monkeydoc @hidden Mouse scale for ios retina devices. Should prob. be in App so @2.png can use it etc.
  143. #end
  144. Property MouseScale:Vec2f()
  145. Return _mouseScale
  146. End
  147. #rem monkeydoc @hidden The internal SDL_Window used by this window.
  148. #end
  149. Property SDLWindow:SDL_Window Ptr()
  150. Return _sdlWindow
  151. End
  152. #rem monkeydoc @hidden The internal SDL_GLContext used by this window.
  153. #end
  154. Property SDLGLContext:SDL_GLContext()
  155. Return _sdlGLContext
  156. End
  157. #rem monkeydoc @hidden
  158. #end
  159. Function AllWindows:Window[]()
  160. Return _allWindows.ToArray()
  161. End
  162. #rem monkeydoc @hidden
  163. #end
  164. Function VisibleWindows:Window[]()
  165. Return _visibleWindows.ToArray()
  166. End
  167. #rem monkeydoc @hidden
  168. #end
  169. Function WindowForID:Window( id:UInt )
  170. Return _windowsByID[id]
  171. End
  172. #rem monkeydoc @hidden
  173. #end
  174. Method SendTouchEvent( event:TouchEvent )
  175. OnTouchEvent( event )
  176. End
  177. #rem monkeydoc @hidden
  178. #end
  179. Method SendWindowEvent( event:WindowEvent )
  180. Select event.Type
  181. Case EventType.WindowMaximized
  182. Case EventType.WindowMinimized
  183. Case EventType.WindowRestored
  184. Case EventType.WindowMoved,EventType.WindowResized
  185. Frame=GetFrame()
  186. _frame=Frame
  187. _weirdHack=True
  188. End
  189. OnWindowEvent( event )
  190. End
  191. #rem monkeydoc Clear the window directly.
  192. ClearWindow can be used to clear the window outside of normal OnRender processing.
  193. #end
  194. Method ClearWindow( color:Color )
  195. SDL_GL_MakeCurrent( _sdlWindow,_sdlGLContext )
  196. Local bounds:=New Recti( 0,0,Frame.Size )
  197. _canvas.Resize( bounds.Size )
  198. _canvas.BeginRender( bounds,New AffineMat3f )
  199. _canvas.Clear( color )
  200. _canvas.EndRender()
  201. SDL_GL_SwapWindow( _sdlWindow )
  202. End
  203. Protected
  204. #rem monkeydoc Called once after a Window has been created.
  205. #end
  206. Method OnCreateWindow() Virtual
  207. End
  208. #rem monkeydoc Theme changed handler.
  209. Called when the App theme changes.
  210. #end
  211. Method OnThemeChanged() override
  212. _clearColor=App.Theme.GetColor( "windowClearColor" )
  213. End
  214. #rem monkeydoc Touch event handler.
  215. Called when the user touches the window on a touch compatible device.
  216. #end
  217. Method OnTouchEvent( event:TouchEvent ) Virtual
  218. End
  219. #rem monkeydoc Window event handler.
  220. Called when the window is sent a window event.
  221. #end
  222. Method OnWindowEvent( event:WindowEvent ) Virtual
  223. Select event.Type
  224. Case EventType.WindowClose
  225. App.Terminate()
  226. Case EventType.WindowResized
  227. App.RequestRender() 'Should maybe do this regardless?
  228. Case EventType.WindowGainedFocus
  229. App.RequestRender() 'Need to do this for KDE on linux?
  230. End
  231. End
  232. Method OnLayout() Override
  233. If _contentView _contentView.Frame=Rect
  234. End
  235. Internal
  236. Method CreateWindow()
  237. If _clearEnabled ClearWindow( _clearColor )
  238. OnCreateWindow()
  239. End
  240. Function CreateNewWindows()
  241. For Local window:=Eachin _newWindows
  242. window.CreateWindow()
  243. End
  244. _newWindows.Clear()
  245. End
  246. Private
  247. Field _sdlWindow:SDL_Window Ptr
  248. Field _sdlGLContext:SDL_GLContext
  249. Field _flags:WindowFlags
  250. Field _maxfudge:Int
  251. Field _rswapInterval:=1
  252. Field _swapInterval:=1
  253. Field _canvas:Canvas
  254. Field _clearColor:=Color.Grey
  255. Field _clearEnabled:=True
  256. Field _contentView:View
  257. Field _minSize:Vec2i
  258. Field _maxSize:Vec2i
  259. Field _frame:Recti
  260. Field _mouseScale:=New Vec2f( 1,1 )
  261. 'Ok, angles glViewport appears To be 'lagging' by one frame, causing weirdness when resizing.
  262. Field _weirdHack:Bool
  263. Global _allWindows:=New Stack<Window>
  264. Global _visibleWindows:=New Stack<Window>
  265. Global _windowsByID:=New Map<UInt,Window>
  266. Global _newWindows:=New Stack<Window>
  267. Method GetDrawableSize:Vec2i()
  268. Local w:Int,h:Int
  269. #If __TARGET__="emscripten"
  270. Local d:Int
  271. emscripten_get_canvas_size( Varptr w,Varptr h,Varptr d )
  272. #Else
  273. SDL_GL_GetDrawableSize( _sdlWindow,Varptr w,Varptr h )
  274. #Endif
  275. Return New Vec2i( w,h )
  276. End
  277. 'Note: also updates _mouseScale
  278. '
  279. Method GetFrame:Recti()
  280. Local dsize:=GetDrawableSize()
  281. Local w:Int,h:Int
  282. SDL_GetWindowSize( _sdlWindow,Varptr w,Varptr h )
  283. _mouseScale=Cast<Vec2f>( dsize )/New Vec2f( w,h )
  284. #If __DESKTOP_TARGET__
  285. Local x:Int,y:Int
  286. SDL_GetWindowPosition( _sdlWindow,Varptr x,Varptr y )
  287. Local dpos:Vec2i=New Vec2f( x,y ) * _mouseScale
  288. Return New Recti( dpos,dpos+dsize )
  289. #else
  290. Return New Recti( 0,0,dsize )
  291. #endif
  292. End
  293. Method GetMinSize:Vec2i()
  294. Local w:Int,h:Int
  295. SDL_GetWindowMinimumSize( _sdlWindow,Varptr w,Varptr h )
  296. Return New Vec2f( w,h ) * _mouseScale
  297. End
  298. Method GetMaxSize:Vec2i()
  299. Local w:Int,h:Int
  300. SDL_GetWindowMaximumSize( _sdlWindow,Varptr w,Varptr h )
  301. Return New Vec2f( w,h ) * _mouseScale
  302. End
  303. Method SetFrame( rect:Recti )
  304. #If __DESKTOP_TARGET__
  305. rect=Cast<Rectf>( rect )/_mouseScale
  306. SDL_SetWindowPosition( _sdlWindow,rect.X,rect.Y )
  307. SDL_SetWindowSize( _sdlWindow,rect.Width,rect.Height )
  308. #endif
  309. End
  310. Method SetMinSize( size:Vec2i )
  311. #If __DESKTOP_TARGET__
  312. size=Cast<Vec2f>( size )/_mouseScale
  313. SDL_SetWindowMinimumSize( _sdlWindow,size.x,size.y )
  314. #endif
  315. End
  316. Method SetMaxSize( size:Vec2i )
  317. #If __DESKTOP_TARGET__
  318. size=Cast<Vec2f>( size )/_mouseScale
  319. SDL_SetWindowMaximumSize( _sdlWindow,size.x,size.y )
  320. #endif
  321. End
  322. Method LayoutWindow()
  323. 'All this polling is a bit ugly...fixme.
  324. '
  325. #If __DESKTOP_TARGET__
  326. If Frame<>_frame
  327. SetFrame( Frame )
  328. Frame=GetFrame()
  329. _frame=Frame
  330. _weirdHack=True
  331. Endif
  332. If MinSize<>_minSize
  333. SetMinSize( MinSize )
  334. MinSize=GetMinSize()
  335. _minSize=MinSize
  336. Endif
  337. If MaxSize<>_maxSize
  338. SetMaxSize( MaxSize )
  339. MaxSize=GetMaxSize()
  340. _maxSize=MaxSize
  341. Endif
  342. #else
  343. Frame=GetFrame()
  344. _frame=Frame
  345. #endif
  346. Measure()
  347. UpdateLayout()
  348. End
  349. #rem monkeydoc @hidden
  350. #end
  351. Method RenderWindow()
  352. If _maxfudge
  353. _maxfudge-=1
  354. App.RequestRender()
  355. Endif
  356. SDL_GL_MakeCurrent( _sdlWindow,_sdlGLContext )
  357. If _swapInterval<>_rswapInterval
  358. SDL_GL_SetSwapInterval( _swapInterval )
  359. _rswapInterval=_swapInterval
  360. Endif
  361. #If __TARGET__="windows"
  362. If _weirdHack
  363. _weirdHack=False
  364. Local attr:Int
  365. If SDL_GL_GetAttribute( SDL_GL_CONTEXT_PROFILE_MASK,Varptr attr )=0
  366. If attr=SDL_GL_CONTEXT_PROFILE_ES SDL_GL_SwapWindow( _sdlWindow )
  367. Endif
  368. Endif
  369. #Endif
  370. Local bounds:=New Recti( 0,0,Frame.Size )
  371. _canvas.Resize( bounds.Size )
  372. _canvas.BeginRender( bounds,New AffineMat3f )
  373. If _clearEnabled _canvas.Clear( _clearColor )
  374. Render( _canvas )
  375. _canvas.EndRender()
  376. SDL_GL_SwapWindow( _sdlWindow )
  377. End
  378. Method Init( title:String,rect:Recti,flags:WindowFlags )
  379. Style=GetStyle( "Window" )
  380. If flags & WindowFlags.Hidden Visible=False
  381. Local x:=(flags & WindowFlags.CenterX) ? SDL_WINDOWPOS_CENTERED Else rect.X
  382. Local y:=(flags & WindowFlags.CenterY) ? SDL_WINDOWPOS_CENTERED Else rect.Y
  383. Local w:=rect.Width,h:=rect.Height
  384. Local sdlFlags:SDL_WindowFlags=SDL_WINDOW_OPENGL
  385. If flags & WindowFlags.Fullscreen
  386. sdlFlags|=SDL_WINDOW_FULLSCREEN
  387. Else If flags & WindowFlags.Maximized
  388. sdlFlags|=SDL_WINDOW_MAXIMIZED
  389. _maxfudge=2
  390. Else If flags & WindowFlags.Minimized
  391. sdlFlags|=SDL_WINDOW_MINIMIZED
  392. Endif
  393. If flags & WindowFlags.Hidden sdlFlags|=SDL_WINDOW_HIDDEN
  394. If flags & WindowFlags.Resizable sdlFlags|=SDL_WINDOW_RESIZABLE
  395. If flags & WindowFlags.Borderless sdlFlags|=SDL_WINDOW_BORDERLESS
  396. If flags & WindowFlags.HighDPI sdlFlags|=SDL_WINDOW_ALLOW_HIGHDPI
  397. _flags=flags
  398. 'Create Window
  399. _sdlWindow=SDL_CreateWindow( title,x,y,w,h,sdlFlags )
  400. If Not _sdlWindow
  401. Print "SDL_GetError="+String.FromCString( SDL_GetError() )
  402. Assert( _sdlWindow,"FATAL ERROR: SDL_CreateWindow failed" )
  403. Endif
  404. 'Create GL context
  405. _sdlGLContext=SDL_GL_CreateContext( _sdlWindow )
  406. If Not _sdlGLContext
  407. Print "SDL_GetError="+String.FromCString( SDL_GetError() )
  408. Assert( _sdlGLContext,"FATAL ERROR: SDL_GL_CreateContext failed" )
  409. Endif
  410. SDL_GL_MakeCurrent( _sdlWindow,_sdlGLContext )
  411. SDL_GL_SetSwapInterval( _rswapInterval )
  412. bbglInit()
  413. _allWindows.Push( Self )
  414. _newWindows.Push( Self )
  415. _windowsByID[SDL_GetWindowID( _sdlWindow )]=Self
  416. If Not (flags & WindowFlags.Hidden) _visibleWindows.Push( Self )
  417. Frame=GetFrame()
  418. _frame=Frame
  419. 'UGLY!!!!!
  420. #If __DESKTOP_TARGET__
  421. If _mouseScale.x<>1 Or _mouseScale.y<>1
  422. Local x:Int=(flags & WindowFlags.CenterX) ? SDL_WINDOWPOS_CENTERED Else rect.X/_mouseScale.x
  423. Local y:Int=(flags & WindowFlags.CenterY) ? SDL_WINDOWPOS_CENTERED Else rect.Y/_mouseScale.y
  424. Local w:Int=rect.Width/_mouseScale.x
  425. Local h:Int=rect.Height/_mouseScale.y
  426. SDL_SetWindowPosition( _sdlWindow,x,y )
  427. SDL_SetWindowSize( _sdlWindow,w,h )
  428. Frame=GetFrame()
  429. _frame=Frame
  430. Endif
  431. #endif
  432. MinSize=GetMinSize()
  433. _minSize=MinSize
  434. MaxSize=GetMaxSize()
  435. _maxSize=MaxSize
  436. _clearColor=App.Theme.GetColor( "windowClearColor" )
  437. _canvas=New Canvas( _frame.Width,_frame.Height )
  438. SetWindow( Self )
  439. UpdateActive()
  440. LayoutWindow()
  441. Activated+=Lambda()
  442. Local flags:=Cast<SDL_WindowFlags>( SDL_GetWindowFlags( _sdlWindow ) )
  443. If (flags & SDL_WINDOW_HIDDEN)
  444. SDL_ShowWindow( _sdlWindow )
  445. SDL_RaiseWindow( _sdlWindow )
  446. _visibleWindows.Push( Self )
  447. Endif
  448. End
  449. Deactivated+=Lambda()
  450. RuntimeError( "Windows cannot be deactivated" )
  451. End
  452. End
  453. End