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
*
* @type {GenericObject<any>}
* @type {any}
* @memberof ButtonTag
*/
private _data;
@ -6459,8 +6459,8 @@ declare namespace OS {
*
* @memberof ButtonTag
*/
set data(v: GenericObject<any>);
get data(): GenericObject<any>;
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<any>}
* @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

View File

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

View File

@ -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<any>}
* @memberof AppDockTag
* @meberof AppDockTag
*/
private _onappselect: TagEventCallback<any>;
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 = $("<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);
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;
}
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);

View File

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

View File

@ -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();
}

View File

@ -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();
});

View File

@ -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;
}

View File

@ -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;
}