Improve application dock:

- Stack all instances of the same application to one single dock button
- Make the dock scrollable by mouse wheel or touch
This commit is contained in:
DanyLE 2022-12-13 22:05:37 +01:00 committed by Dany LE
parent 2ae390ad4b
commit b5863702cb
9 changed files with 150 additions and 81 deletions

17
d.ts/antos.d.ts vendored
View File

@ -6450,7 +6450,7 @@ declare namespace OS {
/** /**
* Custom user data * Custom user data
* *
* @type {GenericObject<any>} * @type {any}
* @memberof ButtonTag * @memberof ButtonTag
*/ */
private _data; private _data;
@ -6459,8 +6459,8 @@ declare namespace OS {
* *
* @memberof ButtonTag * @memberof ButtonTag
*/ */
set data(v: GenericObject<any>); set data(v: any);
get data(): GenericObject<any>; get data(): any;
/** /**
*Creates an instance of ButtonTag. *Creates an instance of ButtonTag.
* @memberof ButtonTag * @memberof ButtonTag
@ -8581,14 +8581,12 @@ declare namespace OS {
*/ */
class AppDockTag extends AFXTag { class AppDockTag extends AFXTag {
/** /**
* variable holds the application select event * Cache of touch event
* callback handle
* *
* @private * @private
* @type {TagEventCallback<any>} * @meberof AppDockTag
* @memberof AppDockTag
*/ */
private _onappselect; private _previous_touch;
/** /**
* Items data of the dock * Items data of the dock
* *
@ -8678,7 +8676,8 @@ declare namespace OS {
* @param {AppDockItemType} item an application dock item entry * @param {AppDockItemType} item an application dock item entry
* @memberof AppDockTag * @memberof AppDockTag
*/ */
newapp(item: AppDockItemType): void; addapp(item: AppDockItemType): void;
private handleAppSelect;
/** /**
* Delete and application entry from the dock. * Delete and application entry from the dock.
* This function will be called when an application * This function will be called when an application

View File

@ -662,7 +662,7 @@ namespace OS {
app.sysdock = dock; app.sysdock = dock;
app.init(); app.init();
app.observable.one("rendered", function () { app.observable.one("rendered", function () {
dock.newapp(data); dock.addapp(data);
}); });
} }

View File

@ -38,15 +38,12 @@ namespace OS {
*/ */
export class AppDockTag extends AFXTag { export class AppDockTag extends AFXTag {
/** /**
* variable holds the application select event * Cache of touch event
* callback handle
* *
* @private * @private
* @type {TagEventCallback<any>} * @meberof AppDockTag
* @memberof AppDockTag
*/ */
private _onappselect: TagEventCallback<any>; private _previous_touch: {x: number, y: number};
/** /**
* Items data of the dock * Items data of the dock
* *
@ -72,7 +69,6 @@ namespace OS {
*/ */
constructor() { constructor() {
super(); super();
this._onappselect = (e) => {};
} }
/** /**
@ -111,6 +107,8 @@ namespace OS {
*/ */
protected init(): void { protected init(): void {
this._items = []; this._items = [];
this._previous_touch = {x: 0, y:0};
} }
/** /**
@ -155,7 +153,7 @@ namespace OS {
let el = undefined; let el = undefined;
for (let it of this.items) { for (let it of this.items) {
it.app.blur(); it.app.blur();
$(it.domel).removeClass(); $(it.domel).removeClass("selected");
if (v && v === it.app) { if (v && v === it.app) {
el = it; el = it;
} }
@ -197,25 +195,68 @@ namespace OS {
* @param {AppDockItemType} item an application dock item entry * @param {AppDockItemType} item an application dock item entry
* @memberof AppDockTag * @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 = $("<afx-button>");
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); this.items.push(item);
const el = $("<afx-button>");
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; 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. * Delete and application entry from the dock.
* This function will be called when an application * This function will be called when an application
@ -236,9 +277,19 @@ namespace OS {
} }
if (i !== -1) { if (i !== -1) {
const appName = this.items[i].app.name;
const el = this.items[i].domel;
delete this.items[i].app; delete this.items[i].app;
this.items.splice(i, 1); 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( const bt = ($(e.target).closest(
"afx-button" "afx-button"
)[0] as any) as ButtonTag; )[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 = [ m.nodes = [
{ text: "__(New window)", dataid: "new" }, { text: "__(New window)", dataid: "new" },
{ text: "__(Show)", dataid: "show" }, { text: "__(Hide all)", dataid: "hide" },
{ text: "__(Hide)", dataid: "hide" }, { text: "__(Close all)", dataid: "quit" },
{ text: "__(Close)", dataid: "quit" },
]; ];
m.onmenuselect = function (evt) { m.onmenuselect = function (evt) {
const item = evt.data.item.data; switch (evt.data.item.data.dataid) {
if (app[item.dataid]) { case "new":
return app[item.dataid](); GUI.launch(bt.data as string, []);
} break;
else case "hide":
{ collection.forEach((el,_) => el.app.hide());
switch (item.dataid) { break;
case "new": case "quit":
GUI.launch(app.name, []); collection.forEach((el,_) => el.app.quit());
break; break;
default:
default: break;
break;
}
} }
}; };
return m.show(e); return m.show(e);
@ -318,6 +367,22 @@ namespace OS {
} }
this.items[index].app.trigger("focus"); 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); define("afx-apps-dock", AppDockTag);

View File

@ -21,22 +21,22 @@ namespace OS {
/** /**
* Custom user data * Custom user data
* *
* @type {GenericObject<any>} * @type {any}
* @memberof ButtonTag * @memberof ButtonTag
*/ */
private _data: GenericObject<any>; private _data: any;
/** /**
* Custom user data setter/gettter * Custom user data setter/gettter
* *
* @memberof ButtonTag * @memberof ButtonTag
*/ */
set data(v: GenericObject<any>) set data(v: any)
{ {
this._data = v; this._data = v;
this.set(v); this.set(v);
} }
get data(): GenericObject<any> get data(): any
{ {
return this._data; return this._data;
} }

View File

@ -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 * @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 * @protected
* @memberof InputTag * @memberof InputTag
@ -232,7 +232,7 @@ namespace OS {
reload(d?: any): void {} reload(d?: any): void {}
/** /**
* Button layout definition * Input layout definition
* *
* @protected * @protected
* @returns {TagLayoutType[]} * @returns {TagLayoutType[]}

View File

@ -508,7 +508,7 @@ namespace OS {
.css("left", left + "px"); .css("left", left + "px");
} }
const doropoff = (e) => { const dropoff = (e) => {
if($(e.target).closest(`[list-id="${list.aid}"]`).length > 0) if($(e.target).closest(`[list-id="${list.aid}"]`).length > 0)
{ {
return; return;
@ -517,10 +517,16 @@ namespace OS {
{ {
return; return;
} }
$(this).hide(); $(this)
$(document).off("click", doropoff); .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).show();
this.calibrate(); this.calibrate();
} }

View File

@ -520,16 +520,7 @@ namespace OS {
this.refs.osmenu.contextmenuHandle = (e, m) => { } this.refs.osmenu.contextmenuHandle = (e, m) => { }
this.refs.systray.contextmenuHandle = (e, m) => { } this.refs.systray.contextmenuHandle = (e, m) => { }
this.refs.pinned.contextmenuHandle = (e, m) => { } this.refs.pinned.contextmenuHandle = (e, m) => { }
this.refs.panel.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);
};
announcer.on("app-pinned", (_) => { announcer.on("app-pinned", (_) => {
this.RefreshPinnedApp(); this.RefreshPinnedApp();
}); });

View File

@ -4,12 +4,17 @@ afx-apps-dock{
padding-top: 0; padding-top: 0;
border-top-right-radius: 0; border-top-right-radius: 0;
border-bottom-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; box-shadow: none;
} }
afx-apps-dock afx-button.selected > button { afx-apps-dock afx-button.selected > button {
background-color: #464646; background-color: #464646;
color: white; 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;
} }

View File

@ -4,14 +4,17 @@ afx-apps-dock{
padding-top: 0; padding-top: 0;
border-top-right-radius: 0; border-top-right-radius: 0;
border-bottom-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; box-shadow: none;
} }
afx-apps-dock afx-button.selected > button { afx-apps-dock afx-button.selected > button {
background-color: #2786F3; background-color: #2786F3;
color: white; 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;
}