Skip to content

Commit

Permalink
list: emit mouse events on root
Browse files Browse the repository at this point in the history
fixes #63598
  • Loading branch information
joaomoreno committed Nov 28, 2018
1 parent 24036d7 commit 4967ca4
Show file tree
Hide file tree
Showing 12 changed files with 67 additions and 30 deletions.
8 changes: 4 additions & 4 deletions src/vs/base/browser/ui/list/list.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,24 +28,24 @@ export interface IListEvent<T> {
export interface IListMouseEvent<T> {
browserEvent: MouseEvent;
element: T | undefined;
index: number;
index: number | undefined;
}

export interface IListTouchEvent<T> {
browserEvent: TouchEvent;
element: T | undefined;
index: number;
index: number | undefined;
}

export interface IListGestureEvent<T> {
browserEvent: GestureEvent;
element: T | undefined;
index: number;
index: number | undefined;
}

export interface IListContextMenuEvent<T> {
browserEvent: UIEvent;
element: T | undefined;
index: number;
index: number | undefined;
anchor: HTMLElement | { x: number; y: number; } | undefined;
}
2 changes: 1 addition & 1 deletion src/vs/base/browser/ui/list/listPaging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ export class PagedList<T> implements IDisposable {
}

get onContextMenu(): Event<IListContextMenuEvent<T>> {
return mapEvent(this.list.onContextMenu, ({ element, index, anchor, browserEvent }) => ({ element: this._model.get(element!), index, anchor, browserEvent }));
return mapEvent(this.list.onContextMenu, ({ element, index, anchor, browserEvent }) => (typeof element === 'undefined' ? { element, index, anchor, browserEvent } : { element: this._model.get(element), index, anchor, browserEvent }));
}

get model(): IPagedModel<T> {
Expand Down
34 changes: 17 additions & 17 deletions src/vs/base/browser/ui/list/listView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -392,35 +392,35 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {

// Events

@memoize get onMouseClick(): Event<IListMouseEvent<T>> { return filterEvent(mapEvent(domEvent(this.domNode, 'click'), e => this.toMouseEvent(e)), e => e.index >= 0); }
@memoize get onMouseDblClick(): Event<IListMouseEvent<T>> { return filterEvent(mapEvent(domEvent(this.domNode, 'dblclick'), e => this.toMouseEvent(e)), e => e.index >= 0); }
@memoize get onMouseMiddleClick(): Event<IListMouseEvent<T>> { return filterEvent(mapEvent(domEvent(this.domNode, 'auxclick'), e => this.toMouseEvent(e as MouseEvent)), e => e.index >= 0 && e.browserEvent.button === 1); }
@memoize get onMouseUp(): Event<IListMouseEvent<T>> { return filterEvent(mapEvent(domEvent(this.domNode, 'mouseup'), e => this.toMouseEvent(e)), e => e.index >= 0); }
@memoize get onMouseDown(): Event<IListMouseEvent<T>> { return filterEvent(mapEvent(domEvent(this.domNode, 'mousedown'), e => this.toMouseEvent(e)), e => e.index >= 0); }
@memoize get onMouseOver(): Event<IListMouseEvent<T>> { return filterEvent(mapEvent(domEvent(this.domNode, 'mouseover'), e => this.toMouseEvent(e)), e => e.index >= 0); }
@memoize get onMouseMove(): Event<IListMouseEvent<T>> { return filterEvent(mapEvent(domEvent(this.domNode, 'mousemove'), e => this.toMouseEvent(e)), e => e.index >= 0); }
@memoize get onMouseOut(): Event<IListMouseEvent<T>> { return filterEvent(mapEvent(domEvent(this.domNode, 'mouseout'), e => this.toMouseEvent(e)), e => e.index >= 0); }
@memoize get onContextMenu(): Event<IListMouseEvent<T>> { return filterEvent(mapEvent(domEvent(this.domNode, 'contextmenu'), e => this.toMouseEvent(e)), e => e.index >= 0); }
@memoize get onTouchStart(): Event<IListTouchEvent<T>> { return filterEvent(mapEvent(domEvent(this.domNode, 'touchstart'), e => this.toTouchEvent(e)), e => e.index >= 0); }
@memoize get onTap(): Event<IListGestureEvent<T>> { return filterEvent(mapEvent(domEvent(this.rowsContainer, TouchEventType.Tap), e => this.toGestureEvent(e)), e => e.index >= 0); }
@memoize get onMouseClick(): Event<IListMouseEvent<T>> { return mapEvent(domEvent(this.domNode, 'click'), e => this.toMouseEvent(e)); }
@memoize get onMouseDblClick(): Event<IListMouseEvent<T>> { return mapEvent(domEvent(this.domNode, 'dblclick'), e => this.toMouseEvent(e)); }
@memoize get onMouseMiddleClick(): Event<IListMouseEvent<T>> { return filterEvent(mapEvent(domEvent(this.domNode, 'auxclick'), e => this.toMouseEvent(e as MouseEvent)), e => e.browserEvent.button === 1); }
@memoize get onMouseUp(): Event<IListMouseEvent<T>> { return mapEvent(domEvent(this.domNode, 'mouseup'), e => this.toMouseEvent(e)); }
@memoize get onMouseDown(): Event<IListMouseEvent<T>> { return mapEvent(domEvent(this.domNode, 'mousedown'), e => this.toMouseEvent(e)); }
@memoize get onMouseOver(): Event<IListMouseEvent<T>> { return mapEvent(domEvent(this.domNode, 'mouseover'), e => this.toMouseEvent(e)); }
@memoize get onMouseMove(): Event<IListMouseEvent<T>> { return mapEvent(domEvent(this.domNode, 'mousemove'), e => this.toMouseEvent(e)); }
@memoize get onMouseOut(): Event<IListMouseEvent<T>> { return mapEvent(domEvent(this.domNode, 'mouseout'), e => this.toMouseEvent(e)); }
@memoize get onContextMenu(): Event<IListMouseEvent<T>> { return mapEvent(domEvent(this.domNode, 'contextmenu'), e => this.toMouseEvent(e)); }
@memoize get onTouchStart(): Event<IListTouchEvent<T>> { return mapEvent(domEvent(this.domNode, 'touchstart'), e => this.toTouchEvent(e)); }
@memoize get onTap(): Event<IListGestureEvent<T>> { return mapEvent(domEvent(this.rowsContainer, TouchEventType.Tap), e => this.toGestureEvent(e)); }

private toMouseEvent(browserEvent: MouseEvent): IListMouseEvent<T> {
const index = this.getItemIndexFromEventTarget(browserEvent.target || null);
const item = index < 0 ? undefined : this.items[index];
const item = typeof index === 'undefined' ? undefined : this.items[index];
const element = item && item.element;
return { browserEvent, index, element };
}

private toTouchEvent(browserEvent: TouchEvent): IListTouchEvent<T> {
const index = this.getItemIndexFromEventTarget(browserEvent.target || null);
const item = index < 0 ? undefined : this.items[index];
const item = typeof index === 'undefined' ? undefined : this.items[index];
const element = item && item.element;
return { browserEvent, index, element };
}

private toGestureEvent(browserEvent: GestureEvent): IListGestureEvent<T> {
const index = this.getItemIndexFromEventTarget(browserEvent.initialTarget || null);
const item = index < 0 ? undefined : this.items[index];
const item = typeof index === 'undefined' ? undefined : this.items[index];
const element = item && item.element;
return { browserEvent, index, element };
}
Expand All @@ -433,7 +433,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
this.rerender(e.scrollTop, e.height);
}
} catch (err) {
console.log('Got bad scroll event:', e);
console.error('Got bad scroll event:', e);
throw err;
}
}
Expand Down Expand Up @@ -499,7 +499,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {

// Util

private getItemIndexFromEventTarget(target: EventTarget | null): number {
private getItemIndexFromEventTarget(target: EventTarget | null): number | undefined {
let element: HTMLElement | null = target as (HTMLElement | null);

while (element instanceof HTMLElement && element !== this.rowsContainer) {
Expand All @@ -516,7 +516,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
element = element.parentElement;
}

return -1;
return undefined;
}

private getRenderRange(renderTop: number, renderHeight: number): IRange {
Expand Down
11 changes: 9 additions & 2 deletions src/vs/base/browser/ui/list/listWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -508,11 +508,18 @@ class MouseController<T> implements IDisposable {
const selection = this.list.getSelection();
reference = reference === undefined ? selection[0] : reference;

const focus = e.index;

if (typeof focus === 'undefined') {
this.list.setFocus([], e.browserEvent);
this.list.setSelection([], e.browserEvent);
return;
}

if (this.multipleSelectionSupport && this.isSelectionRangeChangeEvent(e)) {
return this.changeSelection(e, reference);
}

const focus = e.index;
if (selection.every(s => s !== focus)) {
this.list.setFocus([focus], e.browserEvent);
}
Expand Down Expand Up @@ -556,7 +563,7 @@ class MouseController<T> implements IDisposable {
}

private changeSelection(e: IListMouseEvent<T> | IListTouchEvent<T>, reference: number | undefined): void {
const focus = e.index;
const focus = e.index!;

if (this.isSelectionRangeChangeEvent(e) && reference !== undefined) {
const min = Math.min(reference, focus);
Expand Down
4 changes: 2 additions & 2 deletions src/vs/base/browser/ui/selectBox/selectBoxCustom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -780,8 +780,8 @@ export class SelectBoxList implements ISelectBoxDelegate, IListVirtualDelegate<I
.on(e => this.onMouseUp(e), this, this.toDispose);

this.toDispose.push(
this.selectList.onDidBlur(e => this.onListBlur()),
this.selectList.onMouseOver(e => this.selectList.setFocus([e.index])),
this.selectList.onDidBlur(_ => this.onListBlur()),
this.selectList.onMouseOver(e => typeof e.index !== 'undefined' && this.selectList.setFocus([e.index])),
this.selectList.onFocusChange(e => this.onListFocus(e))
);

Expand Down
9 changes: 6 additions & 3 deletions src/vs/base/browser/ui/tree/dataTree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -289,15 +289,18 @@ export class DataTree<T extends NonNullable<any>, TFilterData = void> implements
// Tree navigation

getParentElement(element: T): T | null {
return this.tree.getParentElement(this.getNode(element)).element;
const node = this.tree.getParentElement(this.getNode(element));
return node && node.element;
}

getFirstElementChild(element: T | null = null): T | null {
return this.tree.getFirstElementChild(this.getNode(element)).element;
const node = this.tree.getFirstElementChild(this.getNode(element));
return node && node.element;
}

getLastElementAncestor(element: T | null = null): T | null {
return this.tree.getLastElementAncestor(this.getNode(element)).element;
const node = this.tree.getLastElementAncestor(this.getNode(element));
return node && node.element;
}

// Implementation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,10 @@ export class NotificationsList extends Themable {
// Context menu to copy message
const copyAction = this._register(this.instantiationService.createInstance(CopyNotificationMessageAction, CopyNotificationMessageAction.ID, CopyNotificationMessageAction.LABEL));
this._register((this.list.onContextMenu(e => {
if (!e.element) {
return;
}

this.contextMenuService.showContextMenu({
getAnchor: () => e.anchor,
getActions: () => [copyAction],
Expand Down
4 changes: 4 additions & 0 deletions src/vs/workbench/parts/debug/browser/breakpointsView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,10 @@ export class BreakpointsView extends ViewletPanel {
}

private onListContextMenu(e: IListContextMenuEvent<IEnablement>): void {
if (!e.element) {
return;
}

const actions: IAction[] = [];
const element = e.element;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -410,6 +410,10 @@ export class RuntimeExtensionsEditor extends BaseEditor {
this._list.splice(0, this._list.length, this._elements);

this._list.onContextMenu((e) => {
if (!e.element) {
return;
}

const actions: IAction[] = [];

actions.push(new ReportExtensionIssueAction(e.element));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,10 @@ export class OpenEditorsView extends ViewletPanel {
}

private onListContextMenu(e: IListContextMenuEvent<OpenEditor | IEditorGroup>): void {
if (!e.element) {
return;
}

const element = e.element;
this.contextMenuService.showContextMenu({
getAnchor: () => e.anchor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,10 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor
}

private onContextMenu(e: IListContextMenuEvent<IListEntry>): void {
if (!e.element) {
return;
}

if (e.element.templateId === KEYBINDING_ENTRY_TEMPLATE_ID) {
this.selectEntry(<IKeybindingItemEntry>e.element);
this.contextMenuService.showContextMenu({
Expand Down
9 changes: 8 additions & 1 deletion src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -316,8 +316,11 @@ class MainPanel extends ViewletPanel {
}

private onListContextMenu(e: IListContextMenuEvent<ISCMRepository>): void {
const repository = e.element;
if (!e.element) {
return;
}

const repository = e.element;
const contextKeyService = this.contextKeyService.createScoped();
const scmProviderKey = contextKeyService.createKey<string | undefined>('scmProvider', void 0);
scmProviderKey.set(repository.provider.contextValue);
Expand Down Expand Up @@ -986,6 +989,10 @@ export class RepositoryPanel extends ViewletPanel {
}

private onListContextMenu(e: IListContextMenuEvent<ISCMResourceGroup | ISCMResource>): void {
if (!e.element) {
return;
}

const element = e.element;
let actions: IAction[];

Expand Down

0 comments on commit 4967ca4

Please sign in to comment.