antos-frontend/src/core/gui.coffee

390 lines
16 KiB
CoffeeScript
Raw Normal View History

2017-08-07 00:49:24 +02:00
self.OS.GUI =
2018-02-01 19:36:09 +01:00
subwindows: new Object()
2018-01-26 18:57:28 +01:00
dialog: undefined
2018-03-01 20:07:27 +01:00
fullscreen: false
2017-08-24 01:53:13 +02:00
htmlToScheme: (html, app, parent) ->
scheme = $.parseHTML html
($ parent).append scheme
riot.mount ($ scheme), { observable: app.observable }
app.scheme = scheme[0]
app.main()
app.show()
loadScheme: (path, app, parent) ->
2018-02-01 19:36:09 +01:00
path.asFileHandler().read (x) ->
2017-08-11 01:58:46 +02:00
return null unless x
2017-08-24 01:53:13 +02:00
_GUI.htmlToScheme x, app, parent
2018-02-01 19:36:09 +01:00
#, (e, s) ->
# _courrier.osfail "Cannot load scheme file: #{path} for #{app.name} (#{app.pid})", e, s
2017-08-27 23:40:02 +02:00
clearTheme: () ->
$ "head link#ostheme"
.attr "href", ""
2017-08-14 00:20:19 +02:00
2018-01-26 18:57:28 +01:00
loadTheme: (name, force) ->
_GUI.clearTheme() if force
2017-08-07 00:49:24 +02:00
path = "resources/themes/#{name}/#{name}.css"
2017-08-11 01:58:46 +02:00
$ "head link#ostheme"
.attr "href", path
2017-08-14 00:20:19 +02:00
pushServices: (srvs) ->
2018-02-16 18:38:14 +01:00
return unless srvs.length > 0
_courrier.observable.one "srvroutineready", () ->
srvs.splice 0, 1
_GUI.pushServices srvs
_GUI.pushService srvs[0]
2018-02-16 18:38:14 +01:00
2018-01-26 18:57:28 +01:00
openDialog: (d, f, title, data) ->
if _GUI.dialog
_GUI.dialog.show()
return
2018-02-01 19:36:09 +01:00
if not _GUI.subwindows[d]
2018-01-26 18:57:28 +01:00
ex = _API.throwe "Dialog"
return _courrier.oserror "Dialog #{d} not found", ex, null
2018-02-01 19:36:09 +01:00
_GUI.dialog = new _GUI.subwindows[d]()
2018-01-26 18:57:28 +01:00
_GUI.dialog.parent = _GUI
_GUI.dialog.handler = f
_GUI.dialog.pid = -1
_GUI.dialog.data = data
_GUI.dialog.title = title
_GUI.dialog.init()
2018-01-22 19:59:08 +01:00
pushService: (ph) ->
arr = ph.split "/"
srv = arr[1]
app = arr[0]
2017-08-27 23:40:02 +02:00
return _PM.createProcess srv, _OS.APP[srv] if _OS.APP[srv]
2018-01-22 19:59:08 +01:00
_GUI.loadApp app,
2018-01-24 01:03:14 +01:00
(a) ->
2018-01-22 19:59:08 +01:00
return _PM.createProcess srv, _OS.APP[srv] if _OS.APP[srv]
(e, s) ->
_courrier.trigger "srvroutineready", srv
2017-08-27 23:40:02 +02:00
_courrier.osfail "Cannot read service script: #{srv} ", e, s
2018-01-22 19:59:08 +01:00
2018-01-26 18:57:28 +01:00
appsByMime: (mime) ->
2018-01-30 14:47:27 +01:00
metas = ( v for k, v of _OS.setting.system.packages when v.app )
2018-01-28 02:01:21 +01:00
mimes = ( m.mimes for m in metas when m)
2018-01-26 18:57:28 +01:00
apps = []
# search app by mimes
f = ( arr, idx ) ->
2018-01-28 02:01:21 +01:00
try
arr.filter (m, i) ->
if mime.match (new RegExp m, "g")
apps.push metas[idx]
return false
2018-01-26 18:57:28 +01:00
return false
2018-01-28 02:01:21 +01:00
catch e
_courrier.osfail "Find app by mimes #{mime}", e, mime
2018-01-26 18:57:28 +01:00
2018-01-26 19:10:00 +01:00
( f m, i if m ) for m, i in mimes
2018-01-26 18:57:28 +01:00
return apps
2018-01-30 19:06:30 +01:00
appsWithServices: () ->
o = {}
o[k] = v for k, v of _OS.setting.system.packages when v.services and v.services.length > 0
o
2018-01-26 18:57:28 +01:00
openWith: (it) ->
return unless it
2018-01-30 14:47:27 +01:00
return _GUI.launch it.app if it.type is "app" and it.app
2018-01-30 19:06:30 +01:00
return _courrier.osinfo "Application#{it.text} is not executable" if it.type is "app"
2018-01-26 18:57:28 +01:00
apps = _GUI.appsByMime ( if it.type is "dir" then "dir" else it.mime )
2018-01-30 14:47:27 +01:00
return _courrier.osinfo "No application available to open #{it.filename}" if apps.length is 0
2018-01-26 18:57:28 +01:00
return _GUI.launch apps[0].app, [it.path] if apps.length is 1
list = ( { text: e.app, icon: e.icon, iconclass: e.iconclass } for e in apps )
_GUI.openDialog "SelectionDialog", ( d ) ->
_GUI.launch d.text, [it.path]
, "Open width", list
2017-08-27 23:40:02 +02:00
forceLaunch: (app, args) ->
console.log "This method is used for developing only, please use the launch method instead"
_PM.killAll app
2018-02-13 04:59:08 +01:00
($ _OS.APP[app].style).remove() if _OS.APP[app] and _OS.APP[app].style
2017-08-27 23:40:02 +02:00
_OS.APP[app] = undefined
_GUI.launch app, args
2018-01-24 01:03:14 +01:00
loadApp: (app, ok, err) ->
2018-01-31 19:20:42 +01:00
path = "os:///packages/#{app}"
path = _OS.setting.system.packages[app].path if _OS.setting.system.packages[app].path
js = path + "/main.js"
2018-02-01 19:36:09 +01:00
2018-01-31 19:20:42 +01:00
js.asFileHandler().read (d) ->
2018-02-01 19:36:09 +01:00
# load app meta data
"#{path}/package.json".asFileHandler().read (data) ->
data.path = path
_OS.APP[app].meta = data if _OS.APP[app]
_OS.APP[v].meta = data for v in data.services if data.services
2018-02-19 23:22:30 +01:00
#load css file
css = "#{path}/main.css"
css.asFileHandler().onready (d) ->
el = $ '<link>', { rel: 'stylesheet', type: 'text/css', 'href': "#{_API.handler.get}/#{css}" }
.appendTo 'head'
_OS.APP[app].style = el[0] if _OS.APP[app]
ok app
, () ->
#launch
ok app
2018-02-01 19:36:09 +01:00
, "json"
#ok app
2018-01-31 19:20:42 +01:00
, "script"
2017-08-27 23:40:02 +02:00
launch: (app, args) ->
if not _OS.APP[app]
2017-08-11 01:58:46 +02:00
# first load it
2018-01-22 19:59:08 +01:00
_GUI.loadApp app,
(a)->
_PM.createProcess a, _OS.APP[a], args
2017-08-26 16:50:13 +02:00
, (e, s) ->
2017-08-11 01:58:46 +02:00
else
2017-08-14 00:20:19 +02:00
# now launch it
2017-08-27 23:40:02 +02:00
if _OS.APP[app]
_PM.createProcess app, _OS.APP[app], args
2017-08-26 16:50:13 +02:00
dock: (app, meta) ->
2017-08-14 00:20:19 +02:00
# dock an application to a dock
# create a data object
2017-08-15 02:56:04 +02:00
data =
icon: null
iconclass: meta.iconclass || ""
2017-08-26 16:50:13 +02:00
app: app
onbtclick: () -> app.toggle()
2018-01-31 19:20:42 +01:00
# TODO: this path is not good, need to create a blob of it
data.icon = "#{_API.handler.get}/#{meta.path}/#{meta.icon}" if meta.icon
2017-08-26 16:50:13 +02:00
# TODO: add default app icon class in system setting
# so that it can be themed
2017-08-14 00:20:19 +02:00
data.iconclass = "fa fa-cogs" if (not meta.icon) and (not meta.iconclass)
dock = $ "#sysdock"
2017-08-26 16:50:13 +02:00
app.one "rendered", () ->
dock.get(0).newapp data
app.sysdock = dock.get(0)
app.appmenu = ($ "[data-id = 'appmenu']", "#syspanel")[0]
2017-08-14 00:20:19 +02:00
app.init()
2018-03-01 20:07:27 +01:00
toggleFullscreen: () ->
2018-02-20 23:07:53 +01:00
el = ($ "body")[0]
2018-03-01 20:07:27 +01:00
if _GUI.fullscreen
return document.exitFullscreen() if document.exitFullscreen
return document.mozCancelFullScreen() if document.mozCancelFullScreen
return document.webkitExitFullscreen() if document.webkitExitFullscreen
return document.exitFullscreen() if document.exitFullscreen
else
return el.requestFullscreen() if el.requestFullscreen
return el.mozRequestFullScreen() if el.mozRequestFullScreen
return el.webkitRequestFullscreen() if el.webkitRequestFullscreen
return el.msRequestFullscreen() if el.msRequestFullscreen
2018-02-20 23:07:53 +01:00
2017-08-14 00:20:19 +02:00
undock: (app) ->
($ "#sysdock").get(0).removeapp app
2017-08-15 02:56:04 +02:00
attachservice: (srv) ->
($ "#syspanel")[0].attachservice srv
srv.init()
detachservice: (srv) ->
($ "#syspanel")[0].detachservice srv
bindContextMenu: (event) ->
handler = (e) ->
if e.contextmenuHandler
e.contextmenuHandler event, ($ "#contextmenu")[0]
else
p = $(e).parent().get(0)
handler p if p isnt ($ "#workspace").get(0)
handler event.target
event.preventDefault()
2018-01-30 19:06:30 +01:00
2017-08-11 01:58:46 +02:00
initDM: ->
2018-03-01 20:07:27 +01:00
($ "body").on 'webkitfullscreenchange mozfullscreenchange fullscreenchange MSFullscreenChange', ()->
_GUI.fullscreen = not _GUI.fullscreen
2017-08-27 23:40:02 +02:00
# check login first
2017-08-11 01:58:46 +02:00
_API.resource "schemes/dm.html", (x) ->
return null unless x
2017-08-15 02:56:04 +02:00
scheme = $.parseHTML x
2017-08-11 01:58:46 +02:00
($ "#wrapper").append scheme
2018-01-26 18:57:28 +01:00
2018-02-28 17:18:00 +01:00
_courrier.observable.one "sysdockloaded", () ->
($ window).bind 'keydown', (event) ->
dock = ($ "#sysdock")[0]
return unless dock
app = dock.get "selectedApp"
return true unless app
c = String.fromCharCode(event.which).toUpperCase()
fnk = undefined
if event.ctrlKey
fnk = "CTRL"
else if event.metaKey
fnk = "META"
else if event.shiftKey
fnk = "SHIFT"
else if event.altKey
fnk = "ALT"
return unless fnk
r = app.shortcut fnk, c
event.preventDefault() if not r
2018-01-26 18:57:28 +01:00
# system menu and dock
riot.mount ($ "#syspanel", $ "#wrapper")
riot.mount ($ "#sysdock", $ "#wrapper"), { items: [] }
2017-08-15 02:56:04 +02:00
# context menu
riot.mount ($ "#contextmenu")
($ "#workspace").contextmenu (e) -> _GUI.bindContextMenu e
2018-01-26 18:57:28 +01:00
# desktop default file manager
desktop = $ "#desktop"
2018-01-30 14:47:27 +01:00
fp = _OS.setting.desktop.path.asFileHandler()
2018-01-26 18:57:28 +01:00
desktop[0].fetch = () ->
fn = () ->
fp.read (d) ->
return _courrier.osfail d.error, (_API.throwe "OS.VFS"), d.error if d.error
items = []
$.each d.result, (i, v) ->
return if v.filename[0] is '.' and not _OS.setting.desktop.showhidden
v.text = v.filename
#v.text = v.text.substring(0,9) + "..." ifv.text.length > 10
v.iconclass = v.type
items.push(v)
desktop[0].set "items", items
desktop[0].refresh()
fp.onready () ->
fn()
, ( e ) -> # try to create the path
console.log "#{fp.path} not found"
name = fp.basename
fp.parent().asFileHandler().mk name, (r) ->
ex = _API.throwe "OS.VFS"
if r.error then _courrier.osfail d.error, ex, d.error else fn()
desktop[0].ready = (e) ->
e.observable = _courrier
window.onresize = () ->
_courrier.trigger "desktopresize"
e.refresh()
desktop[0].set "onlistselect", (d) ->
($ "#sysdock").get(0).set "selectedApp", null
desktop[0].set "onlistdbclick", ( d ) ->
($ "#sysdock").get(0).set "selectedApp", null
it = desktop[0].get "selected"
_GUI.openWith it
2018-01-27 03:16:06 +01:00
#($ "#workingenv").on "click", (e) ->
# desktop[0].set "selected", -1
2018-01-26 18:57:28 +01:00
desktop.on "click", (e) ->
2018-01-27 03:16:06 +01:00
return unless e.target is desktop[0]
desktop[0].set "selected", -1
2018-01-26 18:57:28 +01:00
($ "#sysdock").get(0).set "selectedApp", null
2018-02-28 16:48:09 +01:00
#console.log "desktop clicked"
2018-01-26 18:57:28 +01:00
desktop[0].contextmenuHandler = (e, m) ->
desktop[0].set "selected", -1 if e.target is desktop[0]
2018-01-27 03:16:06 +01:00
($ "#sysdock").get(0).set "selectedApp", null
2018-01-30 19:06:30 +01:00
menu = [
{ text: "Open", dataid: "desktop-open" },
{ text: "Refresh", dataid: "desktop-refresh" }
]
2018-01-31 15:41:32 +01:00
menu = menu.concat ( v for k, v of _OS.setting.desktop.menu)
2018-01-30 19:06:30 +01:00
m.set "items", menu
m.set "onmenuselect", (evt) ->
switch evt.item.data.dataid
when "desktop-open"
it = desktop[0].get "selected"
return _GUI.openWith it if it
it = _OS.setting.desktop.path.asFileHandler()
it.mime = "dir"
_GUI.openWith it
when "desktop-refresh"
desktop[0].fetch()
else
2018-01-31 15:41:32 +01:00
_GUI.launch evt.item.data.app, evt.item.data.args if evt.item.data.app
2018-01-30 19:06:30 +01:00
m.show(e)
2018-01-26 18:57:28 +01:00
desktop[0].fetch()
2018-01-30 14:47:27 +01:00
_courrier.observable.on "VFS", (d) ->
desktop[0].fetch() if d.data.file.hash() is fp.hash() or d.data.file.parent().hash() is fp.hash()
2018-01-31 18:19:02 +01:00
_courrier.ostrigger "desktoploaded"
2018-01-26 18:57:28 +01:00
# mount it
riot.mount desktop
2017-08-27 23:40:02 +02:00
, (e, s) ->
alert "System fall: Cannot init desktop manager"
2018-01-29 19:16:29 +01:00
console.log s, e
buildSystemMenu: () ->
menu =
text: ""
iconclass: "fa fa-eercast"
dataid: "sys-menu-root"
child: [
{
text: "Application",
2018-01-30 14:47:27 +01:00
child: ( v for k, v of _OS.setting.system.packages when v.app ),
2018-01-29 19:16:29 +01:00
dataid: "sys-apps"
iconclass: "fa fa-adn",
onmenuselect: (d) ->
_GUI.launch d.item.data.app
}
]
2018-01-31 15:41:32 +01:00
menu.child = menu.child.concat (v for k, v of _OS.setting.system.menu)
2018-02-20 23:07:53 +01:00
menu.child.push
2018-03-01 20:07:27 +01:00
text: "Toggle Full screen",
2018-02-20 23:07:53 +01:00
dataid: "os-fullsize",
iconclass: "fa fa-tv"
2018-01-29 19:16:29 +01:00
menu.child.push
text: "Log out",
dataid: "sys-logout",
iconclass: "fa fa-user-times"
menu.onmenuselect = (d) ->
return _API.handler.logout() if d.item.data.dataid is "sys-logout"
2018-03-01 20:07:27 +01:00
return _GUI.toggleFullscreen() if d.item.data.dataid is "os-fullsize"
2018-01-29 19:16:29 +01:00
_GUI.launch d.item.data.app unless d.item.data.dataid
2018-01-30 14:47:27 +01:00
($ "[data-id = 'os_menu']", "#syspanel")[0].set "items", [menu]
2018-01-29 19:16:29 +01:00
#console.log menu
2017-08-27 23:40:02 +02:00
login: () ->
2018-01-04 11:51:12 +01:00
_OS.cleanup()
2017-08-27 23:40:02 +02:00
_API.resource "schemes/login.html", (x) ->
return null unless x
scheme = $.parseHTML x
($ "#wrapper").append scheme
($ "#btlogin").click () ->
data =
username: ($ "#txtuser").val(),
password: ($ "#txtpass").val()
_API.handler.login data, (d) ->
if d.error then ($ "#login_error").html d.error else _GUI.startAntOS d.result
2018-02-19 17:05:22 +01:00
($ "#txtpass").keyup (e) ->
($ "#btlogin").click() if e.which is 13
2017-08-27 23:40:02 +02:00
, (e, s) ->
alert "System fall: Cannot init login screen"
startAntOS: (conf) ->
2018-01-26 18:57:28 +01:00
# clean up things
2018-01-04 11:51:12 +01:00
_OS.cleanup()
2018-01-26 18:57:28 +01:00
# get setting from conf
2018-02-27 16:40:36 +01:00
_OS.systemSetting(conf)
#console.log _OS.setting
2017-08-27 23:40:02 +02:00
# load theme
2018-01-27 03:16:06 +01:00
_GUI.loadTheme _OS.setting.appearance.theme
2018-01-26 18:57:28 +01:00
# initDM
2017-08-27 23:40:02 +02:00
_GUI.initDM()
_courrier.observable.one "syspanelloaded", () ->
2018-01-26 18:57:28 +01:00
# TODO load packages list then build system menu
2018-02-01 19:36:09 +01:00
_API.packages.cache (ret) ->
if ret.result
_API.packages.fetch (r) ->
if r.result
for k, v of r.result
v.text = v.name
v.filename = k
v.type = "app"
v.mime = "antos/app"
v.iconclass = "fa fa-adn" unless v.iconclass or v.icon
_OS.setting.system.packages = if r.result then r.result else
_GUI.buildSystemMenu()
# push startup services
# TODO: get services list from user setting
2018-02-28 17:00:08 +01:00
_GUI.pushServices (v for v in _OS.setting.system.startup.services)
2018-02-28 16:40:28 +01:00
(_GUI.launch a) for a in _OS.setting.system.startup.apps
2018-02-28 17:18:00 +01:00
#_GUI.launch "DummyApp"