diff --git a/src/core/BaseDialog.coffee b/src/core/BaseDialog.coffee index 9ee7357..3e8f121 100644 --- a/src/core/BaseDialog.coffee +++ b/src/core/BaseDialog.coffee @@ -191,6 +191,31 @@ class YesNoDialog extends BasicDialog } this.OS.register "YesNoDialog", YesNoDialog +class SelectionDialog extends BasicDialog + constructor: () -> + super "SelectionDialog", { + tag: "afx-list-view", + att: "", + width: 250, + height: 300, + resizable: false, + buttons: [ + { + label: "Ok", onclick: (d) -> + el = d.find "content" + it = el.get "selected" + return unless it + d.handler it if d.handler + d.quit() + }, + { label: "Cancel", onclick: (d) -> d.quit() } + ], + filldata: (d) -> + return unless d.data + (d.find "content").set "items", d.data + } +this.OS.register "SelectionDialog", SelectionDialog + class AboutDialog extends BaseDialog constructor: () -> super "AboutDialog" diff --git a/src/core/BaseModel.coffee b/src/core/BaseModel.coffee index 0682858..391b426 100644 --- a/src/core/BaseModel.coffee +++ b/src/core/BaseModel.coffee @@ -2,9 +2,10 @@ class BaseModel constructor: (@name, @args) -> @observable = riot.observable() @_api = self.OS.API + @_gui = self.OS.GUI me = @ @on "exit", () -> me.quit() - @host = "#desktop" + @host = "#workingenv" @dialog = undefined render: (p) -> @@ -35,10 +36,10 @@ class BaseModel if @dialog @dialog.show() return - if not _GUI.dialog[d] + if not _GUI.dialogs[d] @error "Dialog #{d} not found" return - @dialog = new _GUI.dialog[d]() + @dialog = new _GUI.dialogs[d]() @dialog.parent = @ @dialog.handler = f @dialog.pid = @pid diff --git a/src/core/api.coffee b/src/core/api.coffee index 9897c89..4900ee4 100644 --- a/src/core/api.coffee +++ b/src/core/api.coffee @@ -117,5 +117,5 @@ self.OS.API = catch e err = e return "" if not err - return err.stack + return err diff --git a/src/core/core.coffee b/src/core/core.coffee index 9109249..ea7aa4e 100644 --- a/src/core/core.coffee +++ b/src/core/core.coffee @@ -8,6 +8,7 @@ self.OS or= setting: user: {} applications: {} + desktop: {} appearance: {} courrier: observable: riot.observable() @@ -22,6 +23,8 @@ self.OS or= _courrier.ostrigger "fail", { m: m, e: e, s: s } oserror: (m, e, s) -> _courrier.ostrigger "error", { m: m, e: e, s: s } + osinfo: (m) -> + _courrier.ostrigger "info", { m: m, e: null, s: null } ostrigger: (e, d) -> _courrier.trigger e, { id: 0, data: d, name: "OS" } unregister: (app) -> @@ -33,7 +36,7 @@ self.OS or= _courrier.quota += 1 _courrier.quota register: (name, x) -> - if x.type is 3 then self.OS.GUI.dialog[name] = x else _OS.APP[name] = x + if x.type is 3 then self.OS.GUI.dialogs[name] = x else _OS.APP[name] = x PM: pidalloc: 0 diff --git a/src/core/gui.coffee b/src/core/gui.coffee index cf267db..3bfacf9 100644 --- a/src/core/gui.coffee +++ b/src/core/gui.coffee @@ -1,5 +1,6 @@ self.OS.GUI = - dialog: new Object() + dialogs: new Object() + dialog: undefined htmlToScheme: (html, app, parent) -> scheme = $.parseHTML html ($ parent).append scheme @@ -19,7 +20,8 @@ self.OS.GUI = $ "head link#ostheme" .attr "href", "" - loadTheme: (name) -> + loadTheme: (name, force) -> + _GUI.clearTheme() if force path = "resources/themes/#{name}/#{name}.css" $ "head link#ostheme" .attr "href", path @@ -31,6 +33,21 @@ self.OS.GUI = srvs.splice 0, 1 f i for i in srvs + openDialog: (d, f, title, data) -> + if _GUI.dialog + _GUI.dialog.show() + return + if not _GUI.dialogs[d] + ex = _API.throwe "Dialog" + return _courrier.oserror "Dialog #{d} not found", ex, null + _GUI.dialog = new _GUI.dialogs[d]() + _GUI.dialog.parent = _GUI + _GUI.dialog.handler = f + _GUI.dialog.pid = -1 + _GUI.dialog.data = data + _GUI.dialog.title = title + _GUI.dialog.init() + pushService: (ph) -> arr = ph.split "/" srv = arr[1] @@ -43,6 +60,32 @@ self.OS.GUI = _courrier.trigger "srvroutineready", srv _courrier.osfail "Cannot read service script: #{srv} ", e, s + appsByMime: (mime) -> + metas = ( a.meta for k, a of _OS.APP when a.type is 1) + mimes = ( m.mimes for m in metas ) + apps = [] + # search app by mimes + f = ( arr, idx ) -> + arr.filter (m, i) -> + if mime.match (new RegExp m, "g") + apps.push metas[idx] + return false + return false + + f m, i for m, i in mimes + return apps + + openWith: (it) -> + return unless it + console.log "open #{it.path}" + apps = _GUI.appsByMime ( if it.type is "dir" then "dir" else it.mime ) + return OS.info "No application available to open #{it.filename}" if apps.length is 0 + 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 + forceLaunch: (app, args) -> console.log "This method is used for developing only, please use the launch method instead" _PM.killAll app @@ -129,19 +172,71 @@ self.OS.GUI = return null unless x scheme = $.parseHTML x ($ "#wrapper").append scheme + + # system menu and dock + riot.mount ($ "#syspanel", $ "#wrapper") + riot.mount ($ "#sysdock", $ "#wrapper"), { items: [] } + # context menu riot.mount ($ "#contextmenu") ($ "#workspace").contextmenu (e) -> _GUI.bindContextMenu e - #desktop - desktop = ($ "#desktop") - desktop.on "click", (e) -> - return if e.target isnt desktop.get(0) - ($ "#sysdock").get(0).set "selectedApp", null - desktop.get(0).contextmenuHandler = (e, m) -> - console.log "context menu handler for desktop" - # system menu - riot.mount ($ "#syspanel", $ "#wrapper") - riot.mount ($ "#sysdock", $ "#wrapper"), { items: [] } + + # desktop default file manager + desktop = $ "#desktop" + desktop[0].fetch = () -> + fp = _OS.setting.desktop.path.asFileHandler() + 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 + + ($ "#workingenv").on "click", (e) -> + desktop[0].set "selected", -1 + + desktop.on "click", (e) -> + ($ "#sysdock").get(0).set "selectedApp", null + desktop[0].set "selected", -1 if e.target is desktop[0] + console.log "desktop clicked" + + desktop[0].contextmenuHandler = (e, m) -> + desktop[0].set "selected", -1 if e.target is desktop[0] + console.log "context menu handler for desktop" + + desktop[0].fetch() + _courrier.trigger "desktoploaded" + # mount it + riot.mount desktop , (e, s) -> alert "System fall: Cannot init desktop manager" @@ -161,16 +256,25 @@ self.OS.GUI = alert "System fall: Cannot init login screen" startAntOS: (conf) -> + # clean up things _OS.cleanup() + # get setting from conf + _OS.setting.desktop = conf.desktop if conf.desktop _OS.setting.applications = conf.applications if conf.applications _OS.setting.appearance = conf.appearance if conf.appearance _OS.setting.user = conf.user - # get setting from conf - # load packages list + _OS.setting.desktop.path = "home:///.desktop" unless _OS.setting.desktop.path # load theme - # initDM _GUI.loadTheme "antos" + # initDM _GUI.initDM() _courrier.observable.one "syspanelloaded", () -> - #_GUI.loadApp "CoreServices", (a) -> - _GUI.pushServices ["CoreServices/PushNotification", "CoreServices/Spotlight", "CoreServices/Calendar"] \ No newline at end of file + # TODO load packages list then build system menu + # push startup services + # TODO: get services list from user setting + _GUI.pushServices ["CoreServices/PushNotification", "CoreServices/Spotlight", "CoreServices/Calendar"] + + # startup application here + _courrier.observable.one "desktoploaded", () -> + _GUI.launch "Files" + _GUI.launch "NotePad" \ No newline at end of file diff --git a/src/core/schemes/dm.html b/src/core/schemes/dm.html index 3a1f1bb..bf2c643 100644 --- a/src/core/schemes/dm.html +++ b/src/core/schemes/dm.html @@ -3,7 +3,7 @@
-
-
+ +
diff --git a/src/core/tags/afx-app-window.js b/src/core/tags/afx-app-window.js index ddef264..642de97 100644 --- a/src/core/tags/afx-app-window.js +++ b/src/core/tags/afx-app-window.js @@ -50,8 +50,10 @@ } this.on('mount', function() { var left,top - left = 20 + Math.floor(Math.random() * ($("#desktop").width() - width)) - top = 20 + Math.floor(Math.random() * ($("#desktop").height() - height)) + //left = 20 + Math.floor(Math.random() * ($("#desktop").width() - width)) + //top = 20 + Math.floor(Math.random() * ($("#desktop").height() - height)) + left = ($("#desktop").width() - width)/2 + top = ($("#desktop").height() - height)/2 $(self.refs.window) .css("position",'absolute') .css("left",left + "px") diff --git a/src/core/tags/afx-float-list.js b/src/core/tags/afx-float-list.js index cfbd587..f828a39 100644 --- a/src/core/tags/afx-float-list.js +++ b/src/core/tags/afx-float-list.js @@ -1,8 +1,176 @@ - -
- + +
+
-
\ No newline at end of file diff --git a/src/core/tags/afx-list-view.js b/src/core/tags/afx-list-view.js index 2fed093..0be3e7c 100644 --- a/src/core/tags/afx-list-view.js +++ b/src/core/tags/afx-list-view.js @@ -35,7 +35,10 @@ self.root.get = function(k) { if(k == "selected") - return self.items[self.selidx] + if(self.selidx != -1) + return self.items[self.selidx] + else + return undefined return self[k] } self.root.push = function(e,u) diff --git a/src/core/vfs.coffee b/src/core/vfs.coffee index cf71497..1edf00b 100644 --- a/src/core/vfs.coffee +++ b/src/core/vfs.coffee @@ -39,12 +39,13 @@ class BasicFileHandler return @ if @isRoot() return (@protocol + ":///" + (@genealogy.slice 0 , @genealogy.length - 1).join "/") - onready: (f) -> + onready: (f, err) -> # read meta data return f() if @ready me = @ me.meta (d) -> - return _courrier.osfail d.error, (_API.throwe "OS.VFS"), d.error if d.error + if d.error + return if err then err d else _courrier.osfail d.error, (_API.throwe "OS.VFS"), d.error me.meta = d.result me.ready = true f() diff --git a/src/packages/CoreServices/PushNotification.coffee b/src/packages/CoreServices/PushNotification.coffee index 547b7bf..802104f 100644 --- a/src/packages/CoreServices/PushNotification.coffee +++ b/src/packages/CoreServices/PushNotification.coffee @@ -27,11 +27,12 @@ class PushNotification extends this.OS.GUI.BaseService @nzone = @find "notifyzone" @fzone = @find "feedzone" (@find "btclear").set "onbtclick", (e) -> me.mlist.set "items", [] - #mlist.set "onlistselect", (e) -> console.log e + @subscribe "fail", (e) -> console.log e @subscribe "notification", (o) -> me.pushout 'INFO', o @subscribe "fail", (o) -> me.pushout 'FAIL', o @subscribe "error", (o) -> me.pushout 'ERROR', o - + @subscribe "info", (o) -> me.pushout 'INFO', o + @subscribe "loading", (o) -> me.pending.push o.id me.spin true @@ -59,6 +60,8 @@ class PushNotification extends this.OS.GUI.BaseService icon: o.data.icon, iconclass: o.data.iconclass, closable: true } + console.log o.data.s + console.log o.data.e @mlist.unshift d, true @notifeed d diff --git a/src/packages/Files/main.coffee b/src/packages/Files/main.coffee index 263bb4a..7e6dc86 100644 --- a/src/packages/Files/main.coffee +++ b/src/packages/Files/main.coffee @@ -8,7 +8,7 @@ class Files extends this.OS.GUI.BaseApplication @view = @find "fileview" @navinput = @find "navinput" @navbar = @find "nav-bar" - @currdir = undefined + @currdir = if @args and @args.length > 0 then @args[0].asFileHandler() else "home:///".asFileHandler() @favo = @find "favouri" @clipboard = undefined @@ -17,7 +17,9 @@ class Files extends this.OS.GUI.BaseApplication m.show(e) #@on "fileselect", (d) -> console.log d @on "filedbclick", (e) -> - #if e.data.type is 'dir' then me.chdir e.data.path, true + return unless e.data + return if e.data.type is "dir" + me._gui.openWith e.data @favo.set "onlistselect", (e) -> me.chdir e.data.path ($ @find "btback").click () -> @@ -38,15 +40,17 @@ class Files extends this.OS.GUI.BaseApplication @setting.favorite = [ { text: "Applications", path: 'app:///', iconclass: "fa fa-adn" }, - { text: "Home", path: 'home:///', iconclass: "fa fa-home", selected: true }, + { text: "Home", path: 'home:///', iconclass: "fa fa-home" }, { text: "OS", path: 'os:///', iconclass: "fa fa-inbox" }, { text: "Desktop", path: 'home:///.desktop', iconclass: "fa fa-desktop" }, ] if not @setting.favorite @setting.sidebar = true if @setting.sidebar is undefined @setting.nav = true if @setting.nav is undefined @setting.showhidden = false if @setting.showhidden is undefined - @favo.set "items", @setting.favorite + + @favo.set "items", $.extend true, {}, @setting.favorite @applySetting() + @chdir null applySetting: (k) -> # view setting diff --git a/src/packages/Files/package.json b/src/packages/Files/package.json index 03a28d5..0f6511f 100644 --- a/src/packages/Files/package.json +++ b/src/packages/Files/package.json @@ -9,5 +9,5 @@ "version":"0.1a", "category":"System", "iconclass":"fa fa-hdd-o", - "mimes":["*"] + "mimes":["dir"] } \ No newline at end of file diff --git a/src/packages/NotePad/main.coffee b/src/packages/NotePad/main.coffee index 711cba7..0938f33 100644 --- a/src/packages/NotePad/main.coffee +++ b/src/packages/NotePad/main.coffee @@ -1,5 +1,5 @@ class NotePad extends this.OS.GUI.BaseApplication - constructor: (args) -> + constructor: ( args ) -> super "NotePad", args main: () -> me = @ @@ -9,6 +9,7 @@ class NotePad extends this.OS.GUI.BaseApplication @fileview = @find "fileview" div = @find "datarea" ace.require "ace/ext/language_tools" + @currfile = if @args and @args.length > 0 then @args[0].asFileHandler() else undefined @.editor = ace.edit div @.editor.setOptions { enableBasicAutocompletion: true, @@ -16,7 +17,7 @@ class NotePad extends this.OS.GUI.BaseApplication enableLiveAutocompletion: true, fontSize: "9pt" } - @.editor.completers.push {getCompletions:(editor, session, pos, prefix, callback)->} + @.editor.completers.push { getCompletions: ( editor, session, pos, prefix, callback ) -> } @.editor.getSession().setUseWrapMode true list = @find "modelist" @@ -64,11 +65,20 @@ class NotePad extends this.OS.GUI.BaseApplication @location.set "onlistselect", (e) -> me.chdir e.data.path @location.set "items", [ - { text: "Home", path: 'home:///', iconclass:"fa fa-home", selected:true}, - { text: "OS", path: 'os:///', iconclass:"fa fa-inbox" }, + { text: "Home", path: 'home:///', iconclass: "fa fa-home", selected: true }, + { text: "OS", path: 'os:///', iconclass: "fa fa-inbox" }, { text: "Desktop", path: 'home:///.desktop', iconclass: "fa fa-desktop" }, ] + @open @currfile if @currfile + + open: (file) -> + me = @ + file.read (d) -> + return unless d + me.scheme.set "apptitle", file.basename + me.editor.setValue d, -1 + chdir: (p) -> me = @ me._api.handler.scandir p, @@ -82,10 +92,10 @@ class NotePad extends this.OS.GUI.BaseApplication menu: ()-> menu = [{ - text:"File", - child:[ - {text:"Open", dataid:"#{@name}-Open"}, - {text:"Close", dataid:"#{@name}-Close"} + text: "File", + child: [ + { text: "Open", dataid: "#{@name}-Open" }, + { text: "Close", dataid: "#{@name}-Close" } ] }] menu diff --git a/src/packages/NotePad/package.json b/src/packages/NotePad/package.json index 8119eaa..775719a 100644 --- a/src/packages/NotePad/package.json +++ b/src/packages/NotePad/package.json @@ -9,5 +9,5 @@ "version":"0.1a", "category":"System", "iconclass":"fa fa-pencil-square-o", - "mimes":["*"] + "mimes":[".*"] } \ No newline at end of file diff --git a/src/packages/wTerm/main.coffee b/src/packages/wTerm/main.coffee index 5e21ac1..11cab14 100644 --- a/src/packages/wTerm/main.coffee +++ b/src/packages/wTerm/main.coffee @@ -64,6 +64,7 @@ class wTerm extends this.OS.GUI.BaseApplication @socket.onmessage = (e) -> me.term.write e.data if me.term and e.data @socket.onclose = () -> me.socket = null + me.quit() console.log "socket closed" #el.style.display = "block" cleanup: (e)-> diff --git a/src/themes/antos/antos.css b/src/themes/antos/antos.css index b93c2e2..e3b75f8 100644 --- a/src/themes/antos/antos.css +++ b/src/themes/antos/antos.css @@ -42,6 +42,48 @@ html,body{ cursor: default; padding:0px; } +#desktop > div.float_list_item { + display:block; + background-color:transparent; + text-align: center; + width: 70px; + color: white; + padding:3px; +} + +#desktop > div.float_list_item_selected { + display:block; + background-color: #116cd6; + color:white; + border-radius: 6px; + text-align: center; + width: 70px; + color: white; + padding:3px; +} + +#desktop > div.float_list_item i.file:before{ + content: "\f15b\a"; + font-family: "FontAwesome"; + font-size: 32px; + display: block; + color: white; + font-style: normal; + font-weight: normal; +} +#desktop > div.float_list_item span{ + width: 100%; + word-wrap: break-word; +} +#desktop > div.float_list_item i.dir:before{ + display: block; + content: "\f07b\a"; + font-family: "FontAwesome"; + font-size: 32px; + color: #76D2F9; + font-weight: normal; + font-style: normal; +} input { outline: none; padding: 2px;