From b5863702cb08159b24ee8b8e628501b981d202a0 Mon Sep 17 00:00:00 2001 From: DanyLE Date: Tue, 13 Dec 2022 22:05:37 +0100 Subject: [PATCH] Improve application dock: - Stack all instances of the same application to one single dock button - Make the dock scrollable by mouse wheel or touch --- d.ts/antos.d.ts | 17 ++-- src/core/gui.ts | 2 +- src/core/tags/AppDockTag.ts | 151 ++++++++++++++++++++-------- src/core/tags/ButtonTag.ts | 8 +- src/core/tags/InputTag.ts | 8 +- src/core/tags/StackMenuTag.ts | 14 ++- src/core/tags/SystemPanelTag.ts | 11 +- src/themes/antos_dark/afx-dock.css | 9 +- src/themes/antos_light/afx-dock.css | 11 +- 9 files changed, 150 insertions(+), 81 deletions(-) diff --git a/d.ts/antos.d.ts b/d.ts/antos.d.ts index da8ebc0..78369f8 100644 --- a/d.ts/antos.d.ts +++ b/d.ts/antos.d.ts @@ -6450,7 +6450,7 @@ declare namespace OS { /** * Custom user data * - * @type {GenericObject} + * @type {any} * @memberof ButtonTag */ private _data; @@ -6459,8 +6459,8 @@ declare namespace OS { * * @memberof ButtonTag */ - set data(v: GenericObject); - get data(): GenericObject; + set data(v: any); + get data(): any; /** *Creates an instance of ButtonTag. * @memberof ButtonTag @@ -8581,14 +8581,12 @@ declare namespace OS { */ class AppDockTag extends AFXTag { /** - * variable holds the application select event - * callback handle + * Cache of touch event * * @private - * @type {TagEventCallback} - * @memberof AppDockTag + * @meberof AppDockTag */ - private _onappselect; + private _previous_touch; /** * Items data of the dock * @@ -8678,7 +8676,8 @@ declare namespace OS { * @param {AppDockItemType} item an application dock item entry * @memberof AppDockTag */ - newapp(item: AppDockItemType): void; + addapp(item: AppDockItemType): void; + private handleAppSelect; /** * Delete and application entry from the dock. * This function will be called when an application diff --git a/src/core/gui.ts b/src/core/gui.ts index e17c8bf..cfc24e3 100644 --- a/src/core/gui.ts +++ b/src/core/gui.ts @@ -662,7 +662,7 @@ namespace OS { app.sysdock = dock; app.init(); app.observable.one("rendered", function () { - dock.newapp(data); + dock.addapp(data); }); } diff --git a/src/core/tags/AppDockTag.ts b/src/core/tags/AppDockTag.ts index fef6036..662e87e 100644 --- a/src/core/tags/AppDockTag.ts +++ b/src/core/tags/AppDockTag.ts @@ -38,15 +38,12 @@ namespace OS { */ export class AppDockTag extends AFXTag { /** - * variable holds the application select event - * callback handle - * + * Cache of touch event + * * @private - * @type {TagEventCallback} - * @memberof AppDockTag + * @meberof AppDockTag */ - private _onappselect: TagEventCallback; - + private _previous_touch: {x: number, y: number}; /** * Items data of the dock * @@ -72,7 +69,6 @@ namespace OS { */ constructor() { super(); - this._onappselect = (e) => {}; } /** @@ -111,6 +107,8 @@ namespace OS { */ protected init(): void { this._items = []; + + this._previous_touch = {x: 0, y:0}; } /** @@ -155,7 +153,7 @@ namespace OS { let el = undefined; for (let it of this.items) { it.app.blur(); - $(it.domel).removeClass(); + $(it.domel).removeClass("selected"); if (v && v === it.app) { el = it; } @@ -197,25 +195,68 @@ namespace OS { * @param {AppDockItemType} item an application dock item entry * @memberof AppDockTag */ - newapp(item: AppDockItemType): void { + addapp(item: AppDockItemType): void { + const collection = this.items.filter(it => it.app.name == item.app.name); + let bt = undefined; + if(collection.length == 0) + { + const el = $(""); + bt = el[0] as ButtonTag; + el.appendTo(this); + el[0].uify(this.observable); + bt.set(item); + bt.data = item.app.name; + item.domel = bt; + bt.onbtclick = (e) => { + e.data.stopPropagation(); + this.handleAppSelect(bt); + }; + } + else + { + bt = collection[0].domel; + item.domel = bt; + $(bt).addClass("plural"); + } this.items.push(item); - const el = $(""); - const bt = el[0] as ButtonTag; - el.appendTo(this); - el[0].uify(this.observable); - bt.set(item); - bt.data = item.app; - item.domel = bt; - $(bt).attr("tooltip", `cr:${item.app.title()}`); - bt.onbtclick = (e) => { - e.id = this.aid; - //e.data.item = item; - this._onappselect(e); - item.app.show(); - }; this.selectedApp = item.app; } + private handleAppSelect(bt: ButtonTag) + { + const name = bt.data as any as string; + const collection = this.items.filter(it => it.app.name == name); + if(collection.length == 0) + { + return; + } + if(collection.length == 1) + { + collection[0].app.trigger("focus"); + return; + } + // show the context menu containning a list of application to select + const menu_data = collection.map(e => { + return { + text: (e.app.scheme as WindowTag).apptitle, + icon: e.icon, + iconclass: e.iconclass, + app: e.app + }; + }); + const ctxmenu = $("#contextmenu")[0] as tag.StackMenuTag; + const offset = $(bt).offset(); + ctxmenu.nodes = menu_data; + $(ctxmenu) + .css("left", offset.left) + .css("bottom", $(this).height()); + ctxmenu.onmenuselect = (e) => + { + e.data.item.data.app.show(); + } + ctxmenu.show(); + } + /** * Delete and application entry from the dock. * This function will be called when an application @@ -236,9 +277,19 @@ namespace OS { } if (i !== -1) { + const appName = this.items[i].app.name; + const el = this.items[i].domel; delete this.items[i].app; this.items.splice(i, 1); - $($(this).children()[i]).remove(); + const collection = this.items.filter(it => it.app.name == appName); + if(collection.length == 1) + { + $(el).removeClass("plural"); + } + if(collection.length == 0) + { + $(el).remove(); + } } } @@ -256,28 +307,26 @@ namespace OS { const bt = ($(e.target).closest( "afx-button" )[0] as any) as ButtonTag; - const app = bt.data as application.BaseApplication; + const name = bt.data as any; + const collection = this.items.filter(it => it.app.name == name); m.nodes = [ { text: "__(New window)", dataid: "new" }, - { text: "__(Show)", dataid: "show" }, - { text: "__(Hide)", dataid: "hide" }, - { text: "__(Close)", dataid: "quit" }, + { text: "__(Hide all)", dataid: "hide" }, + { text: "__(Close all)", dataid: "quit" }, ]; m.onmenuselect = function (evt) { - const item = evt.data.item.data; - if (app[item.dataid]) { - return app[item.dataid](); - } - else - { - switch (item.dataid) { - case "new": - GUI.launch(app.name, []); - break; - - default: - break; - } + switch (evt.data.item.data.dataid) { + case "new": + GUI.launch(bt.data as string, []); + break; + case "hide": + collection.forEach((el,_) => el.app.hide()); + break; + case "quit": + collection.forEach((el,_) => el.app.quit()); + break; + default: + break; } }; return m.show(e); @@ -318,6 +367,22 @@ namespace OS { } this.items[index].app.trigger("focus"); }); + + $(this).on("touchstart", e => { + this._previous_touch.x = e.touches[0].pageX; + this._previous_touch.y = e.touches[0].pageY; + }); + $(this).on("touchmove", e => { + const offset = {x:0, y:0}; + offset.x = this._previous_touch.x - e.touches[0].pageX ; + offset.y = this._previous_touch.y - e.touches[0].pageY; + (this as any).scrollLeft += offset.x; + this._previous_touch.x = e.touches[0].pageX; + this._previous_touch.y = e.touches[0].pageY; + }); + $(this).on("wheel", (evt)=>{ + (this as any).scrollLeft += (evt.originalEvent as WheelEvent).deltaY; + }); } } define("afx-apps-dock", AppDockTag); diff --git a/src/core/tags/ButtonTag.ts b/src/core/tags/ButtonTag.ts index 063ae00..df77f20 100644 --- a/src/core/tags/ButtonTag.ts +++ b/src/core/tags/ButtonTag.ts @@ -21,22 +21,22 @@ namespace OS { /** * Custom user data * - * @type {GenericObject} + * @type {any} * @memberof ButtonTag */ - private _data: GenericObject; + private _data: any; /** * Custom user data setter/gettter * * @memberof ButtonTag */ - set data(v: GenericObject) + set data(v: any) { this._data = v; this.set(v); } - get data(): GenericObject + get data(): any { return this._data; } diff --git a/src/core/tags/InputTag.ts b/src/core/tags/InputTag.ts index 0354e2b..5c09820 100644 --- a/src/core/tags/InputTag.ts +++ b/src/core/tags/InputTag.ts @@ -53,9 +53,9 @@ namespace OS { } /** - * Setter: Set the text of the button + * Setter: Set the text of the label * - * Getter: Get the current button test + * Getter: Get the current label test * * @memberof InputTag */ @@ -198,7 +198,7 @@ namespace OS { } /** - * Re-calibrate the button, do nothing in this tag + * Re-calibrate, do nothing in this tag * * @protected * @memberof InputTag @@ -232,7 +232,7 @@ namespace OS { reload(d?: any): void {} /** - * Button layout definition + * Input layout definition * * @protected * @returns {TagLayoutType[]} diff --git a/src/core/tags/StackMenuTag.ts b/src/core/tags/StackMenuTag.ts index cbb2baa..0ffd803 100644 --- a/src/core/tags/StackMenuTag.ts +++ b/src/core/tags/StackMenuTag.ts @@ -508,7 +508,7 @@ namespace OS { .css("left", left + "px"); } - const doropoff = (e) => { + const dropoff = (e) => { if($(e.target).closest(`[list-id="${list.aid}"]`).length > 0) { return; @@ -517,10 +517,16 @@ namespace OS { { return; } - $(this).hide(); - $(document).off("click", doropoff); + $(this) + .css("bottom", "unset") + .css("top", "unset") + .css("left", "unset") + .css("right", "unset") + .hide(); + + $(document).off("click", dropoff); }; - $(document).on("click", doropoff); + $(document).on("click", dropoff); $(this).show(); this.calibrate(); } diff --git a/src/core/tags/SystemPanelTag.ts b/src/core/tags/SystemPanelTag.ts index 5c51aae..f6f4748 100644 --- a/src/core/tags/SystemPanelTag.ts +++ b/src/core/tags/SystemPanelTag.ts @@ -520,16 +520,7 @@ namespace OS { this.refs.osmenu.contextmenuHandle = (e, m) => { } this.refs.systray.contextmenuHandle = (e, m) => { } this.refs.pinned.contextmenuHandle = (e, m) => { } - this.refs.panel.contextmenuHandle = (e, m) => { - let menu = [ - { text: __("Applications and services setting"), dataid: "app&srv" } - ]; - m.nodes = menu; - m.onmenuselect = (evt) => { - GUI.launch("Setting",[]); - } - m.show(e); - }; + this.refs.panel.contextmenuHandle = (e, m) => { }; announcer.on("app-pinned", (_) => { this.RefreshPinnedApp(); }); diff --git a/src/themes/antos_dark/afx-dock.css b/src/themes/antos_dark/afx-dock.css index b4192d5..d47e7e0 100644 --- a/src/themes/antos_dark/afx-dock.css +++ b/src/themes/antos_dark/afx-dock.css @@ -4,12 +4,17 @@ afx-apps-dock{ padding-top: 0; border-top-right-radius: 0; border-bottom-right-radius: 0; - border:1px solid #262626; + border-left:1px solid #262626; + border-right:1px solid #262626; box-shadow: none; } afx-apps-dock afx-button.selected > button { background-color: #464646; color: white; - border: 1px solid #464646; + border: 0; + border-bottom: 3px solid #bb86fc; +} +afx-apps-dock afx-button.plural.selected > button { + border-top: 3px double #646363; } \ No newline at end of file diff --git a/src/themes/antos_light/afx-dock.css b/src/themes/antos_light/afx-dock.css index 4ccb5ca..a228a8c 100644 --- a/src/themes/antos_light/afx-dock.css +++ b/src/themes/antos_light/afx-dock.css @@ -4,14 +4,17 @@ afx-apps-dock{ padding-top: 0; border-top-right-radius: 0; border-bottom-right-radius: 0; - border:1px solid #a6a6a6; + border-left:1px solid #a6a6a6; + border-right:1px solid #a6a6a6; box-shadow: none; } - - afx-apps-dock afx-button.selected > button { background-color: #2786F3; color: white; - /* border: 1px solid #dedede;*/ + border: 0; + border-bottom: 3px solid salmon; +} +afx-apps-dock afx-button.plural.selected > button { + border-top: 3px double #66abfa; } \ No newline at end of file