Module Desktop
	EnableExplicit
	
	;- Constants
	#Timer_Clock        = 0
	#Taskbar_Width      = 72
	#Taskbar_ItemHeight = 40
	#Icon_Size          = 28
	#Menu_W             = 240
	#Menu_Rail_W        = 52
	#Menu_Header_H      = 32
	#Menu_Row_H         = 44
	#Menu_Icon_Size     = 22
	
	; Hit-test return values for the start menu
	Enumeration
		#Hit_None     = -1
		#Hit_Settings = -2
		#Hit_Logout   = -3
	EndEnumeration
	
	;- Globals
	; Colors
	Global Color_Bar_Bg       = RGB( 28,  28,  40)
	Global Color_Bar_Active   = RGB( 52,  52,  72)
	Global Color_Accent       = RGB(100, 120, 255)
	Global Color_Icon         = RGBA(220, 220, 220, 255)
	Global Color_Menu_Bg      = RGB( 36,  36,  52)
	Global Color_Menu_Rail    = RGB( 22,  22,  34)
	Global Color_Menu_Header  = RGB( 22,  22,  34)
	Global Color_Menu_Hover   = RGB( 55,  55,  78)
	Global Color_Menu_Sep     = RGB( 48,  48,  65)
	Global Color_Menu_Text    = RGB(200, 200, 215)
	Global Color_Menu_Dim     = RGB(110, 110, 135)
	Global Color_Logout_Hover = RGB( 65,  30,  35)
	Global Color_Logout_Icon  = RGBA(200,  90,  90, 255)
	
	Global IconFont = LoadFont(#PB_Any, "sans-serif", 18)
	Global MenuFont = LoadFont(#PB_Any, "sans-serif", 13)
	
	; Desktop windows
	Global TaskBarWindow
	Global ClockLabel
	Global StartButton
	Global StartMenuWindow
	
	; App registry
	Structure App
		Name.s
		IconImg.i
		Proc.i
		ID.s
	EndStructure
	#MaxInstalledApps = 32
	Global Dim AppRegistry.App(#MaxInstalledApps)
	Global _AppCount
	Global _MenuCanvas
	Global _MenuHover = #Hit_None
	
	; System shortcut icons (created in Open)
	Global _IconSettings
	Global _IconLogout
	
	; Window manager state
	Structure Window
		Window.i
		Button.i
		Name.s
		Icon.i
	EndStructure
	Global _ActiveWindow
	Global NewList WindowManager.Window()
	
	;- Private declarations
	Declare _MakeIconImage(Label.s, Size = #Icon_Size, Color = 0)
	Declare _MenuHeight()
	Declare _HitTest(MX, MY)
	Declare _RebuildMenu()
	Declare _DrawMenu()
	Declare _CloseMenu()
	Declare _FindByWindow(Win)
	Declare _FindByButton(Btn)
	Declare _DrawButton()
	Declare _SetActiveButton()
	Declare _RebuildButtons()
	Declare _LoadInstalledAppsCallback(Success, DataString.s)
	Declare Handler_Logout()
	Declare LogoutCallback(Success, Response.s)
	Declare Handler_Resize()
	Declare Handler_Clock()
	Declare Handler_StartButton()
	Declare Handler_StartMenu_Focus()
	Declare Handler_MenuCanvas()
	Declare Handler_TaskbarButton()
	Declare Handler_AppClose()
	Declare Handler_AppActivate()
	
	;- Public procedures
	Procedure Open(Username.s)
		Protected Width, Height
		Protected *AppProc
		
		Width  = DesktopWidth(0)
		Height = DesktopHeight(0)
		
		; System shortcut icons — pass explicit colors at creation time
		_IconSettings = _MakeIconImage("⚙", #Menu_Icon_Size, Color_Logout_Icon)
		_IconLogout   = _MakeIconImage("⏻", #Menu_Icon_Size, Color_Logout_Icon)
		
		TaskBarWindow = OpenWindow(#PB_Any, 0, 0, #Taskbar_Width, Height, "", #PB_Window_BorderLess)
		BindEvent(#PB_Event_ActivateWindow, @Handler_AppActivate(), TaskBarWindow)
		StickyWindow(TaskBarWindow, #True)
		SetWindowColor(TaskBarWindow, Color_Bar_Bg)
		
		StartButton = ButtonGadget(#PB_Any, 0, 0, #Taskbar_Width, #Taskbar_ItemHeight, "≡")
		BindGadgetEvent(StartButton, @Handler_StartButton())
		
		ClockLabel = TextGadget(#PB_Any, 0, Height - #Taskbar_ItemHeight, #Taskbar_Width, #Taskbar_ItemHeight, "", #PB_Text_Center | #PB_Text_VerticalCenter)
		SetGadgetColor(ClockLabel, #PB_Gadget_FrontColor, Color_Menu_Text)
		Handler_Clock()
		AddWindowTimer(TaskBarWindow, #Timer_Clock, 1000)
		BindEvent(#PB_Event_Timer, @Handler_Clock(), TaskBarWindow)
		
		StartMenuWindow = OpenWindow(#PB_Any, #Taskbar_Width + 4, 0, #Menu_W, 100, "", #PB_Window_BorderLess | #PB_Window_Invisible)
		StickyWindow(StartMenuWindow, #True)
		_MenuCanvas = CanvasGadget(#PB_Any, 0, 0, #Menu_W, 100)
		BindGadgetEvent(_MenuCanvas, @Handler_MenuCanvas())
		
		BindEvent(#PB_Event_SizeDesktop,      @Handler_Resize())
		BindEvent(#PB_Event_DeactivateWindow, @Handler_StartMenu_Focus(), StartMenuWindow)
		
		AppRuntime::Init()
		!p_appproc = fileexplorer$f_open;
		InstallApp("File Explorer", *AppProc, "📁")
		!p_appproc = webbrowser$f_open;
		InstallApp("Web Browser", *AppProc, "🌐")
		!p_appproc = appmanager$f_open;
		InstallApp("App Manager", *AppProc, "📦")
		Handler_Resize()
		
		HTTPRequest(#PB_HTTP_Get, "/api/apps/list", "", @_LoadInstalledAppsCallback())
	EndProcedure
	
	Procedure InstallApp(AppName.s, *LaunchProc, Icon.s = "")
		Protected Slot
		Protected Label.s
		
		If _AppCount >= #MaxInstalledApps : ProcedureReturn : EndIf
		
		Slot  = _AppCount
		Label = Icon
		If Label = "" : Label = Left(AppName, 2) : EndIf
		
		AppRegistry(Slot)\Name    = AppName
		AppRegistry(Slot)\Proc    = *LaunchProc
		AppRegistry(Slot)\IconImg = _MakeIconImage(Label, #Menu_Icon_Size)
		
		_AppCount + 1
		_RebuildMenu()
	EndProcedure
	
	Procedure Register(AppName.s, Win, Icon.s = "")
		Protected Y, GadgetList, Btn
		Protected Label.s
		
		AddElement(WindowManager())
		WindowManager()\Window = Win
		WindowManager()\Name   = AppName
		
		Label = Icon
		If Label = "" : Label = Left(AppName, 2) : EndIf
		WindowManager()\Icon = _MakeIconImage(Label)
		
		Y          = #Taskbar_ItemHeight + (ListIndex(WindowManager()) * #Taskbar_ItemHeight)
		GadgetList = UseGadgetList(WindowID(TaskBarWindow))
		Btn        = CanvasGadget(#PB_Any, 0, Y, #Taskbar_Width, #Taskbar_ItemHeight)
		UseGadgetList(GadgetList)
		
		WindowManager()\Button = Btn
		SetGadgetData(Btn, Win)
		SetWindowData(Win, Btn)
		
		BindGadgetEvent(Btn, @Handler_TaskbarButton())
		BindEvent(#PB_Event_CloseWindow,    @Handler_AppClose(),    Win)
		BindEvent(#PB_Event_ActivateWindow, @Handler_AppActivate(), Win)
		
		_ActiveWindow = Win
		_SetActiveButton()
	EndProcedure
	
	Procedure Unregister(Win)
		If Not _FindByWindow(Win) : ProcedureReturn : EndIf
		UnbindEvent(#PB_Event_CloseWindow,    @Handler_AppClose(),    Win)
		UnbindEvent(#PB_Event_ActivateWindow, @Handler_AppActivate(), Win)
		UnbindGadgetEvent(WindowManager()\Button, @Handler_TaskbarButton())
		FreeGadget(WindowManager()\Button)
		CloseWindow(Win)
		DeleteElement(WindowManager())
		If _ActiveWindow = Win : _ActiveWindow = GetActiveWindow() : EndIf
		_RebuildButtons()
	EndProcedure
	
	Procedure InstallThirdPartyApp(AppID.s, ManifestJSON.s, Permissions.s, Icon.s = "")
		Protected Slot, i
		Protected AppName.s, Label.s, N.s
		
		Slot = -1
		For i = 0 To _AppCount - 1
			If AppRegistry(i)\ID = AppID : Slot = i : Break : EndIf
		Next
		
		If Slot < 0
			If _AppCount >= #MaxInstalledApps : ProcedureReturn : EndIf
			Slot = _AppCount
			_AppCount + 1
		Else
			If IsImage(AppRegistry(Slot)\IconImg) : FreeImage(AppRegistry(Slot)\IconImg) : EndIf
		EndIf
		
		AppName = AppID
		If ParseJSON(0, ManifestJSON)
			N = GetJSONString(GetJSONMember(JSONValue(0), "name"))
			If N <> "" : AppName = N : EndIf
			FreeJSON(0)
		EndIf
		
		AppRegistry(Slot)\Name = AppName
		AppRegistry(Slot)\ID   = AppID
		
		!(function() {
		!  var _id = v_appid, _m = v_manifestjson, _p = v_permissions;
		!  desktop$a_AppRegistry.array[v_slot]._Proc = function() {
		!    appruntime$f_launch(_id, _m, _p);
		!  };
		!})();
		
		Label = Icon
		If Label = "" : Label = "📦" : EndIf
		AppRegistry(Slot)\IconImg = _MakeIconImage(Label, #Menu_Icon_Size)
		
		_RebuildMenu()
	EndProcedure
	
	Procedure UninstallThirdPartyApp(AppID.s)
		Protected i, j
		For i = 0 To _AppCount - 1
			If AppRegistry(i)\ID = AppID
				If IsImage(AppRegistry(i)\IconImg) : FreeImage(AppRegistry(i)\IconImg) : EndIf
				; Compact the registry
				For j = i To _AppCount - 2
					AppRegistry(j)\Name    = AppRegistry(j + 1)\Name
					AppRegistry(j)\ID      = AppRegistry(j + 1)\ID
					AppRegistry(j)\IconImg = AppRegistry(j + 1)\IconImg
					AppRegistry(j)\Proc    = AppRegistry(j + 1)\Proc
					!desktop$a_AppRegistry.array[v_j]._Proc = desktop$a_AppRegistry.array[v_j + 1]._Proc;
				Next
				AppRegistry(_AppCount - 1)\Name    = ""
				AppRegistry(_AppCount - 1)\ID      = ""
				AppRegistry(_AppCount - 1)\IconImg = 0
				AppRegistry(_AppCount - 1)\Proc    = 0
				!desktop$a_AppRegistry.array[desktop$g__appcount]._Proc = 0;
				_AppCount - 1
				_RebuildMenu()
				ProcedureReturn
			EndIf
		Next
	EndProcedure
	
	;- Private procedures
	Procedure _MakeIconImage(Label.s, Size = #Icon_Size, Color = 0)
		Protected Img
		
		Img = CreateImage(#PB_Any, Size, Size, 32, RGBA(0, 0, 0, 0))
		If Not IsImage(Img) : ProcedureReturn 0 : EndIf
		If StartVectorDrawing(ImageVectorOutput(Img))
			VectorFont(IconFont, Size * 0.65)
			If Color = 0
				VectorSourceColor(Color_Icon)
			Else
				VectorSourceColor(Color)
			EndIf
			
			;MovePathCursor((Size - VectorTextWidth(Label)) / 2, (Size - VectorTextHeight(Label)) / 2)
			;In 3.20 DrawVectorText() draws vertically centered?
			MovePathCursor((Size - VectorTextWidth(Label)) / 2, Size - (VectorTextHeight(Label) / 2))
			DrawVectorText(Label)
			StopVectorDrawing()
		EndIf
		ProcedureReturn Img
	EndProcedure
	
	Procedure _MenuHeight()
		Protected RightH = #Menu_Header_H + _AppCount * #Menu_Row_H + 8
		Protected MinH   = 2 * #Menu_Row_H + 16   ; always room for both rail shortcuts
		If RightH < MinH : ProcedureReturn MinH : EndIf
		ProcedureReturn RightH
	EndProcedure
	
	; Returns app index (>=0), #Hit_Settings, #Hit_Logout, or #Hit_None.
	Procedure _HitTest(MX, MY)
		Protected H, LogoutY, SettingsY, RY
		
		H = _MenuHeight()
		If MX < #Menu_Rail_W
			; Left rail — system shortcuts are bottom-anchored
			LogoutY   = H - #Menu_Row_H
			SettingsY = H - 2 * #Menu_Row_H
			If MY >= SettingsY And MY < LogoutY
				ProcedureReturn #Hit_Settings
			ElseIf MY >= LogoutY And MY < H
				ProcedureReturn #Hit_Logout
			EndIf
		Else
			; Right panel — app rows below header
			RY = MY - #Menu_Header_H
			If RY >= 0 And RY < _AppCount * #Menu_Row_H
				ProcedureReturn RY / #Menu_Row_H
			EndIf
		EndIf
		ProcedureReturn #Hit_None
	EndProcedure
	
	Procedure _RebuildMenu()
		Protected H = _MenuHeight()
		If IsWindow(StartMenuWindow) : ResizeWindow(StartMenuWindow, #PB_Ignore, #PB_Ignore, #Menu_W, H) : EndIf
		If IsGadget(_MenuCanvas)     : ResizeGadget(_MenuCanvas, 0, 0, #Menu_W, H)                      : EndIf
		_DrawMenu()
	EndProcedure
	
	Procedure _DrawMenu()
		If Not IsGadget(_MenuCanvas) : ProcedureReturn : EndIf
		If Not StartDrawing(CanvasOutput(_MenuCanvas)) : ProcedureReturn : EndIf
		
		Protected W = OutputWidth()
		Protected H = OutputHeight()
		Protected TH, IX, IY, i, Y
		
		; ── Left rail ────────────────────────────────────────────────────────
		Box(0, 0, #Menu_Rail_W, H, Color_Menu_Rail)
		
		Protected SettingsY = H - 2 * #Menu_Row_H
		Protected LogoutY   = H - #Menu_Row_H
		
		If _MenuHover = #Hit_Settings
			Box(0, SettingsY, #Menu_Rail_W, #Menu_Row_H, Color_Menu_Hover)
		EndIf
		If _MenuHover = #Hit_Logout
			Box(0, LogoutY, #Menu_Rail_W, #Menu_Row_H, Color_Logout_Hover)
		EndIf
		
		If IsImage(_IconSettings)
			IX = (#Menu_Rail_W - #Menu_Icon_Size) / 2
			IY = SettingsY + (#Menu_Row_H - #Menu_Icon_Size) / 2
			DrawAlphaImage(ImageID(_IconSettings), IX, IY)
		EndIf
		If IsImage(_IconLogout)
			IX = (#Menu_Rail_W - #Menu_Icon_Size) / 2
			IY = LogoutY + (#Menu_Row_H - #Menu_Icon_Size) / 2
			DrawAlphaImage(ImageID(_IconLogout), IX, IY)
		EndIf
		
		; Separator between rail and right panel
		Box(#Menu_Rail_W, 0, 1, H, Color_Menu_Sep)
		
		; ── Right panel ──────────────────────────────────────────────────────
		Box(#Menu_Rail_W + 1, 0, W - #Menu_Rail_W - 1, H, Color_Menu_Bg)
		
		; Header
		Box(#Menu_Rail_W + 1, 0, W - #Menu_Rail_W - 1, #Menu_Header_H, Color_Menu_Header)
		DrawingMode(#PB_2DDrawing_Transparent)
		If IsFont(MenuFont) : DrawingFont(FontID(MenuFont)) : EndIf
		TH = TextHeight("A")
		DrawText(#Menu_Rail_W + 14, (#Menu_Header_H - TH) / 2, "Apps", Color_Menu_Dim)
		
		; App rows
		Y = #Menu_Header_H
		For i = 0 To _AppCount - 1
			If _MenuHover = i
				DrawingMode(#PB_2DDrawing_Default)
				Box(#Menu_Rail_W + 1, Y, W - #Menu_Rail_W - 1, #Menu_Row_H, Color_Menu_Hover)
			EndIf
			If IsImage(AppRegistry(i)\IconImg)
				IX = #Menu_Rail_W + 12
				IY = Y + (#Menu_Row_H - #Menu_Icon_Size) / 2
				DrawAlphaImage(ImageID(AppRegistry(i)\IconImg), IX, IY)
			EndIf
			DrawingMode(#PB_2DDrawing_Transparent)
			TH = TextHeight("A")
			DrawText(#Menu_Rail_W + 12 + #Menu_Icon_Size + 8,
			         Y + (#Menu_Row_H - TH) / 2,
			         AppRegistry(i)\Name, Color_Menu_Text)
			Y + #Menu_Row_H
		Next
		
		StopDrawing()
	EndProcedure
	
	Procedure _CloseMenu()
		HideWindow(StartMenuWindow, #True)
		_MenuHover = #Hit_None
		_DrawMenu()
	EndProcedure
	
	Procedure _FindByWindow(Win)
		ForEach WindowManager()
			If WindowManager()\Window = Win : ProcedureReturn #True : EndIf
		Next
	EndProcedure
	
	Procedure _FindByButton(Btn)
		ForEach WindowManager()
			If WindowManager()\Button = Btn : ProcedureReturn #True : EndIf
		Next
	EndProcedure
	
	Procedure _DrawButton()
		Protected Active, W, H
		
		Active = Bool(WindowManager()\Window = _ActiveWindow And _ActiveWindow <> 0)
		If Not IsGadget(WindowManager()\Button) : ProcedureReturn : EndIf
		If StartDrawing(CanvasOutput(WindowManager()\Button))
			W = OutputWidth()
			H = OutputHeight()
			If Active
				Box(0, 0, W, H, Color_Bar_Active)
				Box(0, H / 4, 3, H / 2, Color_Accent)
			Else
				Box(0, 0, W, H, Color_Bar_Bg)
			EndIf
			If IsImage(WindowManager()\Icon)
				DrawAlphaImage(ImageID(WindowManager()\Icon), (W - #Icon_Size) / 2, (H - #Icon_Size) / 2)
			EndIf
			StopDrawing()
		EndIf
	EndProcedure
	
	Procedure _SetActiveButton()
		ForEach WindowManager()
			_DrawButton()
		Next
	EndProcedure
	
	Procedure _RebuildButtons()
		ForEach WindowManager()
			ResizeGadget(WindowManager()\Button, 0, #Taskbar_ItemHeight + (ListIndex(WindowManager()) * #Taskbar_ItemHeight), #Taskbar_Width, #Taskbar_ItemHeight)
			_DrawButton()
		Next
	EndProcedure
	
	Procedure _LoadInstalledAppsCallback(Success, DataString.s)
		Protected Root, Total, Item, ManiNode, PermNode, PermCount, i, j
		Protected AppID.s, Icon.s, Perms.s, ManiStr.s
		
		If Not Success Or Not ParseJSON(0, DataString) : ProcedureReturn : EndIf
		Root  = JSONValue(0)
		Total = JSONArraySize(Root)
		
		For i = 0 To Total - 1
			Item     = GetJSONElement(Root, i)
			ManiNode = GetJSONMember(Item, "manifest")
			AppID    = GetJSONString(GetJSONMember(Item, "app_id"))
			Icon     = GetJSONString(GetJSONMember(ManiNode, "icon"))
			
			PermNode  = GetJSONMember(Item, "permissions")
			PermCount = JSONArraySize(PermNode)
			Perms     = "["
			For j = 0 To PermCount - 1
				If j > 0 : Perms + "," : EndIf
				Perms + ~"\"" + GetJSONString(GetJSONElement(PermNode, j)) + ~"\""
			Next
			Perms + "]"
			
			; Re-serialise the manifest object to a JSON string for InstallThirdPartyApp
			ManiStr = "{" +
			          ~"\"id\":\""      + GetJSONString(GetJSONMember(ManiNode, "id"))      + ~"\"," +
			          ~"\"name\":\""    + GetJSONString(GetJSONMember(ManiNode, "name"))    + ~"\"," +
			          ~"\"version\":\"" + GetJSONString(GetJSONMember(ManiNode, "version")) + ~"\"," +
			          ~"\"icon\":\""    + ReplaceString(Icon, ~"\"", ~"\\\"")               + ~"\"," +
			          ~"\"entry\":\""   + GetJSONString(GetJSONMember(ManiNode, "entry"))   + ~"\"}"
			
			InstallThirdPartyApp(AppID, ManiStr, Perms, Icon)
		Next
		FreeJSON(0)
	EndProcedure
	
	;- Event handlers
	Procedure Handler_Resize()
		Protected Width  = DesktopWidth(0)
		Protected Height = DesktopHeight(0)
		ResizeWindow(TaskBarWindow, 0, 0, #Taskbar_Width, Height)
		ResizeGadget(ClockLabel, 0, Height - #Taskbar_ItemHeight, #Taskbar_Width, #Taskbar_ItemHeight)
	EndProcedure
	
	Procedure Handler_Clock()
		SetGadgetText(ClockLabel, FormatDate("%hh:%ii:%ss", Date()))
	EndProcedure
	
	Procedure Handler_StartButton()
		HideWindow(StartMenuWindow, #False)
		SetActiveWindow(StartMenuWindow)
	EndProcedure
	
	Procedure Handler_StartMenu_Focus()
		_CloseMenu()
	EndProcedure
	
	Procedure Handler_Logout()
		HTTPRequest(#PB_HTTP_Post, "/api/auth/logout", "", @LogoutCallback())
	EndProcedure
	
	Procedure LogoutCallback(Success, Response.s)
		!location.reload()
	EndProcedure
	
	Procedure Handler_MenuCanvas()
		Protected EType, MX, MY, Hit
		
		EType = EventType()
		MX    = GetGadgetAttribute(_MenuCanvas, #PB_Canvas_MouseX)
		MY    = GetGadgetAttribute(_MenuCanvas, #PB_Canvas_MouseY)
		Hit   = _HitTest(MX, MY)
		
		Select EType
			Case #PB_EventType_MouseMove
				If Hit <> _MenuHover
					_MenuHover = Hit
					_DrawMenu()
				EndIf
				
			Case #PB_EventType_MouseLeave
				If _MenuHover <> #Hit_None
					_MenuHover = #Hit_None
					_DrawMenu()
				EndIf
				
			Case #PB_EventType_LeftButtonUp
				Select Hit
					Case #Hit_Settings
						_CloseMenu()
						!settings$f_open();
						
					Case #Hit_Logout
						_CloseMenu()
						Handler_Logout()
						
					Default
						If Hit >= 0 And Hit < _AppCount And AppRegistry(Hit)\Proc <> 0
							_CloseMenu()
							!desktop$a_AppRegistry.array[v_hit]._Proc();
						EndIf
				EndSelect
		EndSelect
	EndProcedure
	
	Procedure Handler_TaskbarButton()
		Protected Btn, Win
		If EventType() <> #PB_EventType_LeftButtonUp : ProcedureReturn : EndIf
		Btn = EventGadget()
		Win = GetGadgetData(Btn)
		If Not IsWindow(Win) : ProcedureReturn : EndIf
		If _ActiveWindow = Win
			HideWindow(Win, #True)
			_ActiveWindow = 0
		Else
			HideWindow(Win, #False)
			SetActiveWindow(Win)
			_ActiveWindow = Win
		EndIf
		_SetActiveButton()
	EndProcedure
	
	Procedure Handler_AppClose()
		Protected Win = EventWindow()
		If Not _FindByWindow(Win) : ProcedureReturn : EndIf
		UnbindEvent(#PB_Event_CloseWindow,    @Handler_AppClose(),    Win)
		UnbindEvent(#PB_Event_ActivateWindow, @Handler_AppActivate(), Win)
		UnbindGadgetEvent(WindowManager()\Button, @Handler_TaskbarButton())
		FreeGadget(WindowManager()\Button)
		DeleteElement(WindowManager())
		If _ActiveWindow = Win : _ActiveWindow = GetActiveWindow() : EndIf
		_RebuildButtons()
		CloseWindow(Win)
	EndProcedure
	
	Procedure Handler_AppActivate()
		Protected Win = EventWindow()
		If Win = TaskBarWindow : ProcedureReturn : EndIf
		_ActiveWindow = Win
		_SetActiveButton()
	EndProcedure
	
EndModule

; IDE Options = SpiderBasic 3.20 (Windows - x86)
; CursorPosition = 95
; FirstLine = 82
; Folding = BAAAg
; iOSAppOrientation = 0
; AndroidAppCode = 0
; AndroidAppOrientation = 0
; EnableXP
; DPIAware
; CompileSourceDirectory