diff --git a/src/atlasComponents/userAnnotations/annotationList/annotationList.component.ts b/src/atlasComponents/userAnnotations/annotationList/annotationList.component.ts index 2ffb0a698f1adc4d4d4d133c40a6da36b665fbf2..525f5eaa5dad6a2ca706664963bda383d8bef9ac 100644 --- a/src/atlasComponents/userAnnotations/annotationList/annotationList.component.ts +++ b/src/atlasComponents/userAnnotations/annotationList/annotationList.component.ts @@ -19,7 +19,8 @@ const README = 'EXAMPLE OF READ ME TEXT' styleUrls: ['./annotationList.style.css'], providers: [ ComponentStore, - ] + ], + exportAs: 'annotationListCmp' }) export class AnnotationList { diff --git a/src/atlasComponents/userAnnotations/directives/annotationEv.directive.ts b/src/atlasComponents/userAnnotations/directives/annotationEv.directive.ts new file mode 100644 index 0000000000000000000000000000000000000000..8e92f09776e2b5eaecb653061fda92af02bbf981 --- /dev/null +++ b/src/atlasComponents/userAnnotations/directives/annotationEv.directive.ts @@ -0,0 +1,42 @@ +import { Directive, EventEmitter, Input, OnDestroy, Output } from "@angular/core"; +import { Subscription } from "rxjs"; +import { ModularUserAnnotationToolService } from "../tools/service"; +import { TCallback } from "../tools/type"; + +type TAnnotationEv<T extends keyof TCallback> = { + type: T + callArg?: TCallback[T]['callArg'] +} + +@Directive({ + selector: '[annotation-event-directive]', + exportAs: 'annotationEventDir' +}) +export class AnnotationEventDirective implements OnDestroy{ + + @Input('annotation-event-directive-filter') + filter: (keyof TCallback)[] = null + + @Output('annotation-event-directive') + ev = new EventEmitter<TAnnotationEv<keyof TCallback>>() + + private subs: Subscription[] = [] + + constructor(svc: ModularUserAnnotationToolService){ + this.subs.push( + svc.toolEvents.subscribe(<T extends keyof TCallback>(event: { type: T } & TCallback[T]['callArg']) => { + if (this.filter?.includes) { + if (this.filter.includes(event.type)) { + this.ev.emit(event) + } + } else { + this.ev.emit(event) + } + }) + ) + } + + ngOnDestroy(){ + while(this.subs.length > 0)this.subs.pop().unsubscribe() + } +} diff --git a/src/atlasComponents/userAnnotations/module.ts b/src/atlasComponents/userAnnotations/module.ts index efeb89edaa368240e3ed73ee4e82548d44fd5de9..c4ecb05849b239e3528e7c411769ec474dd98555 100644 --- a/src/atlasComponents/userAnnotations/module.ts +++ b/src/atlasComponents/userAnnotations/module.ts @@ -13,6 +13,7 @@ import { AnnotationVisiblePipe } from "./annotationVisible.pipe"; import { FileInputModule } from "src/getFileInput/module"; import { ZipFilesOutputModule } from "src/zipFilesOutput/module"; import { FilterAnnotationsBySpace } from "./filterAnnotationBySpace.pipe"; +import { AnnotationEventDirective } from "./directives/annotationEv.directive"; @NgModule({ imports: [ @@ -35,11 +36,13 @@ import { FilterAnnotationsBySpace } from "./filterAnnotationBySpace.pipe"; SingleAnnotationClsIconPipe, AnnotationVisiblePipe, FilterAnnotationsBySpace, + AnnotationEventDirective, ], exports: [ AnnotationMode, AnnotationList, - AnnotationSwitch + AnnotationSwitch, + AnnotationEventDirective ] }) diff --git a/src/atlasComponents/userAnnotations/tools/line.ts b/src/atlasComponents/userAnnotations/tools/line.ts index f48247a65abe28e6c92cf334cf1ec85cb4c81b6e..1303612f991d1cadc53a1ce73ddf9f043babca52 100644 --- a/src/atlasComponents/userAnnotations/tools/line.ts +++ b/src/atlasComponents/userAnnotations/tools/line.ts @@ -270,6 +270,12 @@ export class ToolLine extends AbsToolClass<Line> implements IAnnotationTools, On this.selectedLine = null this.managedAnnotations$.next(this.managedAnnotations) if (this.callback) { + this.callback({ + type: 'message', + message: 'Line added.', + action: 'Open', + actionCallback: () => this.callback({ type: 'showList' }) + }) this.callback({ type: 'paintingEnd' }) } } diff --git a/src/atlasComponents/userAnnotations/tools/point.ts b/src/atlasComponents/userAnnotations/tools/point.ts index 7ea3b5f55ecc64e0ac20e7b7a9cded0502a1ba80..2dcafc2490a82b2dacb3bf5180b7457947de2770 100644 --- a/src/atlasComponents/userAnnotations/tools/point.ts +++ b/src/atlasComponents/userAnnotations/tools/point.ts @@ -141,11 +141,24 @@ export class ToolPoint extends AbsToolClass<Point> implements IAnnotationTools, '@type': 'siibra-ex/annotation/point' }) this.addAnnotation(pt) - - /** - * deselect on selecting a point - */ - this.callback({ type: 'paintingEnd' }) + + if (this.callback) { + + /** + * message + */ + this.callback({ + type: 'message', + message: `Point added`, + action: 'Open', + actionCallback: () => this.callback({ type: 'showList' }) + }) + + /** + * deselect on selecting a point + */ + this.callback({ type: 'paintingEnd' }) + } }), /** diff --git a/src/atlasComponents/userAnnotations/tools/poly.ts b/src/atlasComponents/userAnnotations/tools/poly.ts index c0a65bca5b81b91eb6e918b5c6fd13f7565ce475..c33662c2afc022ae8240884c629946587057b662 100644 --- a/src/atlasComponents/userAnnotations/tools/poly.ts +++ b/src/atlasComponents/userAnnotations/tools/poly.ts @@ -343,9 +343,18 @@ export class ToolPolygon extends AbsToolClass<Polygon> implements IAnnotationToo this.selectedPoly.points[0], this.lastAddedPoint ) - this.callback({ - type: 'paintingEnd', - }) + + if (this.callback) { + this.callback({ + type: 'message', + message: 'Polyline added.', + action: 'Open', + actionCallback: () => this.callback({ type: 'showList' }) + }) + this.callback({ + type: 'paintingEnd', + }) + } return } } diff --git a/src/atlasComponents/userAnnotations/tools/poly/poly.style.css b/src/atlasComponents/userAnnotations/tools/poly/poly.style.css index 06677c5fea38a957e76e0f0e816aa9bd43bc3328..35465c66c929b4586f68c6121822f345cdb8ea21 100644 --- a/src/atlasComponents/userAnnotations/tools/poly/poly.style.css +++ b/src/atlasComponents/userAnnotations/tools/poly/poly.style.css @@ -3,3 +3,8 @@ point-update-cmp width: 100%; display: block; } + +:host >>> .mat-chip-list-wrapper +{ + flex-wrap: wrap; +} diff --git a/src/atlasComponents/userAnnotations/tools/service.ts b/src/atlasComponents/userAnnotations/tools/service.ts index 292c9394151bc786dec8889e6e95b8c8cd9ff4cf..fde183e33b5d8fd56059d857f4c5dfb600502350 100644 --- a/src/atlasComponents/userAnnotations/tools/service.ts +++ b/src/atlasComponents/userAnnotations/tools/service.ts @@ -7,13 +7,14 @@ import { map, switchMap, filter, shareReplay, pairwise } from "rxjs/operators"; import { viewerStateSelectedTemplatePureSelector, viewerStateViewerModeSelector } from "src/services/state/viewerState/selectors"; import { NehubaViewerUnit } from "src/viewerModule/nehuba"; import { NEHUBA_INSTANCE_INJTKN } from "src/viewerModule/nehuba/util"; -import { AbsToolClass, ANNOTATION_EVENT_INJ_TOKEN, IAnnotationEvents, IAnnotationGeometry, INgAnnotationTypes, INJ_ANNOT_TARGET, TAnnotationEvent, ClassInterface, TCallbackFunction, TSands, TGeometryJson, TNgAnnotationLine } from "./type"; +import { AbsToolClass, ANNOTATION_EVENT_INJ_TOKEN, IAnnotationEvents, IAnnotationGeometry, INgAnnotationTypes, INJ_ANNOT_TARGET, TAnnotationEvent, ClassInterface, TCallbackFunction, TSands, TGeometryJson, TNgAnnotationLine, TCallback } from "./type"; import { switchMapWaitFor } from "src/util/fn"; import { Polygon } from "./poly"; import { Line } from "./line"; import { Point } from "./point"; import { FilterAnnotationsBySpace } from "../filterAnnotationBySpace.pipe"; import { retry } from 'common/util' +import { MatSnackBar } from "@angular/material/snack-bar"; const LOCAL_STORAGE_KEY = 'userAnnotationKey' @@ -113,7 +114,9 @@ export class ModularUserAnnotationToolService implements OnDestroy{ }[] = [] private mousePosReal: [number, number, number] + public toolEvents = new Subject() private handleToolCallback: TCallbackFunction = arg => { + this.toolEvents.next(arg) switch (arg.type) { case 'paintingEnd': { this.deselectTools() @@ -122,6 +125,19 @@ export class ModularUserAnnotationToolService implements OnDestroy{ case 'requestManAnnStream': { return this.managedAnnotations$ } + case 'message': { + const d = (arg as TCallback['message']['callArg'] & { type: any }) + const { message, actionCallback, action = null } = d + this.snackbar.open(message, action, { + duration: 3000 + }).afterDismissed().subscribe(({ dismissedByAction }) => { + if (dismissedByAction && actionCallback) actionCallback() + }) + return + } + case 'showList': { + return + } } } @@ -209,6 +225,7 @@ export class ModularUserAnnotationToolService implements OnDestroy{ constructor( private store: Store<any>, + private snackbar: MatSnackBar, @Inject(INJ_ANNOT_TARGET) annotTarget$: Observable<HTMLElement>, @Inject(ANNOTATION_EVENT_INJ_TOKEN) private annotnEvSubj: Subject<TAnnotationEvent<keyof IAnnotationEvents>>, @Optional() @Inject(NEHUBA_INSTANCE_INJTKN) nehubaViewer$: Observable<NehubaViewerUnit>, diff --git a/src/atlasComponents/userAnnotations/tools/type.ts b/src/atlasComponents/userAnnotations/tools/type.ts index 90ed9c48e461bb0271f76a6ac4feef2984f2aada..1716457a166eea87cc6b9943b4c3ebed3538c03a 100644 --- a/src/atlasComponents/userAnnotations/tools/type.ts +++ b/src/atlasComponents/userAnnotations/tools/type.ts @@ -165,6 +165,18 @@ export type TCallback = { callArg: {} returns: Observable<IAnnotationGeometry[]> } + message: { + callArg: { + message: string + action?: string + actionCallback?: () => void + } + returns: void + } + showList: { + callArg: {} + returns: void + } } export type TCallbackFunction = <T extends keyof TCallback>(arg: TCallback[T]['callArg'] & { type: T }) => TCallback[T]['returns'] | void diff --git a/src/viewerModule/viewerCmp/viewerCmp.template.html b/src/viewerModule/viewerCmp/viewerCmp.template.html index 182ad5dd899093fb43efb6d2bbba926cdd1cc144..0d8938c15635d9856ee6ba14a3c16933a0225528 100644 --- a/src/viewerModule/viewerCmp/viewerCmp.template.html +++ b/src/viewerModule/viewerCmp/viewerCmp.template.html @@ -9,8 +9,10 @@ <div *ngIf="(viewerMode$ | async) === ARIA_LABELS.VIEWER_MODE_ANNOTATING"> <mat-drawer-container class="mat-drawer-content-overflow-visible w-100 h-100 position-absolute invisible" [hasBackdrop]="false"> - <mat-drawer #annotationDrawer + <mat-drawer #annotationDrawer="matDrawer" mode="side" + (annotation-event-directive)="annotationDrawer.open()" + [annotation-event-directive-filter]="['showList']" [autoFocus]="false" [disableClose]="true" class="p-0 pe-all col-10 col-sm-10 col-md-5 col-lg-4 col-xl-3 col-xxl-2">