From e03ea6e0002eaf6f015871bc0e5815039b6f60a9 Mon Sep 17 00:00:00 2001
From: Xiao Gui <xgui3783@gmail.com>
Date: Sun, 26 Aug 2018 07:51:26 +0200
Subject: [PATCH] WIP layer control

---
 src/atlasViewer/atlasViewer.component.ts      | 18 +++---
 src/atlasViewer/atlasViewer.template.html     |  4 +-
 src/services/stateStore.service.ts            | 12 +++-
 src/ui/databrowser/databrowser.component.ts   |  5 --
 .../dedicated/dedicated.component.ts          | 47 +++++++-------
 .../dedicated/dedicated.template.html         | 32 ++--------
 src/ui/layerbrowser/layerbrowser.component.ts | 63 ++++++++++++++++++-
 .../layerbrowser/layerbrowser.template.html   | 15 ++++-
 .../nehubaContainer.component.ts              | 33 +++++-----
 .../nehubaViewer/nehubaViewer.component.ts    | 12 ++--
 10 files changed, 145 insertions(+), 96 deletions(-)

diff --git a/src/atlasViewer/atlasViewer.component.ts b/src/atlasViewer/atlasViewer.component.ts
index 0aaf3777b..db6b45721 100644
--- a/src/atlasViewer/atlasViewer.component.ts
+++ b/src/atlasViewer/atlasViewer.component.ts
@@ -5,7 +5,6 @@ import { Observable, Subscription, combineLatest } from "rxjs";
 import { map, filter, distinctUntilChanged } from "rxjs/operators";
 import { AtlasViewerDataService } from "./atlasViewer.dataService.service";
 import { WidgetServices } from "./widgetUnit/widgetService.service";
-import { DataBrowserUI } from "../ui/databrowser/databrowser.component";
 import { LayoutMainSide } from "../layouts/mainside/mainside.component";
 import { Chart } from 'chart.js'
 import { AtlasViewerConstantsServices, SUPPORT_LIBRARY_MAP } from "./atlasViewer.constantService.service";
@@ -13,7 +12,6 @@ import { BsModalService } from "ngx-bootstrap/modal";
 import { ModalUnit } from "./modalUnit/modalUnit.component";
 import { AtlasViewerURLService } from "./atlasViewer.urlService.service";
 import { ToastComponent } from "../components/toast/toast.component";
-import { WidgetUnit } from "./widgetUnit/widgetUnit.component";
 import { AtlasViewerAPIServices } from "./atlasViewer.apiService.service";
 import { PluginServices } from "./atlasViewer.pluginService.service";
 
@@ -218,8 +216,10 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit {
           return
         }
         this.dedicatedViewComponentRef = this.toastContainer.createComponent(this.toastComponentFactory)
-        this.dedicatedViewComponentRef.instance.messageContainer.createEmbeddedView(this.dedicatedViewerToast)
-        this.dedicatedViewComponentRef.instance.dismissable = false
+        // this.dedicatedViewComponentRef.instance.messageContainer.createEmbeddedView(this.dedicatedViewerToast)
+        this.dedicatedViewComponentRef.instance.message = `hello`
+        this.dedicatedViewComponentRef.instance.dismissable = true
+        this.dedicatedViewComponentRef.instance.timeout = 1000
       })
     )
 
@@ -404,11 +404,11 @@ export class AtlasViewer implements OnDestroy, OnInit, AfterViewInit {
     }
   }
 
-  clearDedicatedView() {
-    this.store.dispatch({
-      type: UNLOAD_DEDICATED_LAYER
-    })
-  }
+  // clearDedicatedView() {
+  //   this.store.dispatch({
+  //     type: UNLOAD_DEDICATED_LAYER
+  //   })
+  // }
 
   toggleSidePanel(panelName:string){
     this.store.dispatch({
diff --git a/src/atlasViewer/atlasViewer.template.html b/src/atlasViewer/atlasViewer.template.html
index c1b156795..41b53f945 100644
--- a/src/atlasViewer/atlasViewer.template.html
+++ b/src/atlasViewer/atlasViewer.template.html
@@ -139,10 +139,10 @@
 </markdown-dom>
 
 <ng-template #dedicatedViewerToast>
-  <div *ngIf = "dedicatedView$ | async">
+  <!-- <div *ngIf = "dedicatedView$ | async">
     <span dedicatedviewertext>displaying : {{ dedicatedView$ | async | getFilenameFromPathname }}. </span>
     <span (click) = "clearDedicatedView()" class = "btn btn-link">clear</span>
-  </div>
+  </div> -->
   <div *ngIf = "!(dedicatedView$ | async)">
     no special data is being displayed right now
   </div>
diff --git a/src/services/stateStore.service.ts b/src/services/stateStore.service.ts
index 0f49f1f49..909b93ef3 100644
--- a/src/services/stateStore.service.ts
+++ b/src/services/stateStore.service.ts
@@ -41,6 +41,7 @@ export interface ViewerStateInterface{
   userLandmarks : UserLandmark[]
 
   navigation : any | null
+  dedicatedView : string[]
 }
 
 export interface AtlasAction extends Action{
@@ -49,7 +50,7 @@ export interface AtlasAction extends Action{
   selectTemplate? : any
   selectParcellation? : any
   selectRegions? : any[]
-  dedicatedView? : string 
+  dedicatedView? : string
 
   landmarks : UserLandmark[]
 
@@ -175,12 +176,17 @@ export function uiState(state:UIStateInterface = {mouseOverSegment:null, focused
 export function viewerState(state:ViewerStateInterface,action:AtlasAction){
   switch(action.type){
     case LOAD_DEDICATED_LAYER:
+      const dedicatedView = state.dedicatedView
+        ? state.dedicatedView.concat(action.dedicatedView)
+        : [action.dedicatedView]
       return Object.assign({},state,{
-        dedicatedView : action.dedicatedView
+        dedicatedView 
       })
     case UNLOAD_DEDICATED_LAYER:
       return Object.assign({},state,{
-        dedicatedView : null
+        dedicatedView : state.dedicatedView
+          ? state.dedicatedView.filter(dv => dv !== action.dedicatedView)
+          : []
       })
     case NEWVIEWER:
       return Object.assign({},state,{
diff --git a/src/ui/databrowser/databrowser.component.ts b/src/ui/databrowser/databrowser.component.ts
index 84f56fbd2..3e94701d8 100644
--- a/src/ui/databrowser/databrowser.component.ts
+++ b/src/ui/databrowser/databrowser.component.ts
@@ -270,11 +270,6 @@ export class DataBrowserUI implements OnDestroy,OnInit{
     return `${file.name ? file.name : file.path}`
   }
 
-  handleDedicatedViewString = (dedicatedViewString:string|null)=>this.store.dispatch({
-    type : dedicatedViewString ? LOAD_DEDICATED_LAYER : UNLOAD_DEDICATED_LAYER,
-    dedicatedView : dedicatedViewString
-  })
-
   dataWindowRegistry: Set<string> = new Set()
 
   handleTreeNodeClick(obj:{inputItem:any,node:TreeComponent},searchResult:any){
diff --git a/src/ui/fileviewer/dedicated/dedicated.component.ts b/src/ui/fileviewer/dedicated/dedicated.component.ts
index ca9f143b8..73f0904dd 100644
--- a/src/ui/fileviewer/dedicated/dedicated.component.ts
+++ b/src/ui/fileviewer/dedicated/dedicated.component.ts
@@ -1,8 +1,9 @@
 import { Component, OnDestroy, Input } from "@angular/core";
 import { Store, select } from "@ngrx/store";
-import { DedicatedViewState, File, UNLOAD_DEDICATED_LAYER, LOAD_DEDICATED_LAYER } from "../../../services/stateStore.service";
+import { DedicatedViewState, File, ADD_NG_LAYER, REMOVE_NG_LAYER, NgViewerStateInterface } from "../../../services/stateStore.service";
 import { Observable, Subscription } from "rxjs";
 import { filter, map } from "rxjs/operators";
+import { getActiveColorMapFragmentMain } from "../../nehubaContainer/nehubaContainer.component";
 
 
 @Component({
@@ -16,50 +17,44 @@ import { filter, map } from "rxjs/operators";
 export class DedicatedViewer implements OnDestroy{
   @Input() searchResultFile : File
 
-  private dedicatedView$ : Observable<string|null>
-  private dedicatedViewSubscription : Subscription
-  private dedicatedView : string | null
+  private ngLayers$ : Observable<NgViewerStateInterface>
+  private ngLayersSubscription : Subscription
+  private ngLayers : Set<string> = new Set()
 
   constructor(private store:Store<DedicatedViewState>){
-    this.dedicatedView$ = this.store.pipe(
-      select('viewerState'),
-      filter(state=>typeof state !== 'undefined' && state !== null),
-      map(state=>state.dedicatedView)
+    this.ngLayers$ = this.store.pipe(
+      select('ngViewerState')
     )
 
-    this.dedicatedViewSubscription = this.dedicatedView$.subscribe(url => this.dedicatedView = url)
+    this.ngLayersSubscription = this.ngLayers$.subscribe(layersInterface => this.ngLayers = new Set(layersInterface.layers.map(l => l.source)))
   }
 
   get isShowing(){
-    return this.dedicatedView === `nifti://${this.searchResultFile.url}`
-  }
-
-  get isObstructed(){
-    return typeof this.dedicatedView !== 'undefined' &&
-      this.dedicatedView !== null &&
-      this.dedicatedView !== `nifti://${this.searchResultFile.url}`
+    return this.ngLayers.has(`nifti://${this.searchResultFile.url}`)
   }
 
   ngOnDestroy(){
-    this.dedicatedViewSubscription.unsubscribe()
+    this.ngLayersSubscription.unsubscribe()
   }
 
   showDedicatedView(){
     this.store.dispatch({
-      type : LOAD_DEDICATED_LAYER,
-      dedicatedView : `nifti://${this.searchResultFile.url}`
+      type : ADD_NG_LAYER,
+      layer : {
+        name : this.searchResultFile.url,
+        source : `nifti://${this.searchResultFile.url}`,
+        mixability : 'nonmixable',
+        shader : getActiveColorMapFragmentMain()
+      }
     })
   }
 
   removeDedicatedView(){
     this.store.dispatch({
-      type : UNLOAD_DEDICATED_LAYER,
+      type : REMOVE_NG_LAYER,
+      layer : {
+        name : this.searchResultFile.url
+      }
     })
   }
-  
-  get nowShowing():string|null{
-    return this.dedicatedView ? 
-      this.dedicatedView.split('/')[this.dedicatedView.split('/').length-1]:
-      null
-  }
 }
\ No newline at end of file
diff --git a/src/ui/fileviewer/dedicated/dedicated.template.html b/src/ui/fileviewer/dedicated/dedicated.template.html
index 254a40c54..4b4fd2b39 100644
--- a/src/ui/fileviewer/dedicated/dedicated.template.html
+++ b/src/ui/fileviewer/dedicated/dedicated.template.html
@@ -1,32 +1,10 @@
-<span *ngIf = "!isShowing" >
-  <span 
-    *ngIf = "isObstructed">
-
-    <span class = "obstructedText">
-      The viewer is currently displaying another dataset:
-    </span>
-    
-    <div class = "well">
-      {{ nowShowing }}
-    </div>
-    <span class = "obstructedText">
-      This dataset can be displayed after the currently shown dataset is cleared.
-    </span>
-    <span (click)="removeDedicatedView()" class = "btn btn-link">
-      clear the currently shown dataset
-    </span>
-  </span>
-
-  <span
-    (click) = "showDedicatedView()"
-    class = "btn btn-link"
-    *ngIf = "!isObstructed">
-
-    show this dataset in the viewer 
-  </span>
+<span 
+  (click) = "showDedicatedView()"
+  *ngIf = "!isShowing"
+  class = "btn btn-link">
 
+  show this dataset in the viewer 
 </span>
-
 <span 
   (click) = "removeDedicatedView()"
   *ngIf = "isShowing"
diff --git a/src/ui/layerbrowser/layerbrowser.component.ts b/src/ui/layerbrowser/layerbrowser.component.ts
index 20a838992..0c011deb3 100644
--- a/src/ui/layerbrowser/layerbrowser.component.ts
+++ b/src/ui/layerbrowser/layerbrowser.component.ts
@@ -1,5 +1,9 @@
-import { Component, Input } from "@angular/core";
+import { Component, Input, OnDestroy } from "@angular/core";
 import { AtlasViewerLayerInterface } from "../../util/pipes/newViewerDistinctViewToLayer.pipe";
+import { Observable, Subscription } from "rxjs";
+import { isDefined, ViewerStateInterface } from "../../services/stateStore.service";
+import { Store, select } from "@ngrx/store";
+import { filter, delay, distinctUntilChanged } from "rxjs/operators";
 
 
 @Component({
@@ -8,9 +12,47 @@ import { AtlasViewerLayerInterface } from "../../util/pipes/newViewerDistinctVie
   styleUrls : [ './layerbrowser.style.css' ]
 })
 
-export class LayerBrowser{
+export class LayerBrowser implements OnDestroy{
   @Input() layers : AtlasViewerLayerInterface[] = []
 
+  ngLayers : NgLayerInterface[] = []
+  newViewer$ : Observable<any>
+  subscription : Subscription
+  disposeHandler : any
+
+  constructor(private store : Store<ViewerStateInterface>){
+    this.newViewer$ = this.store.pipe(
+      select('viewerState'),
+      filter(state=>isDefined(state) && isDefined(state.templateSelected)),
+      distinctUntilChanged((o,n) => o.templateSelected.name === n.templateSelected.name)
+    )
+
+    this.subscription = this.newViewer$.pipe(
+      delay(0)
+    ).subscribe(() => {
+      this.layerChangedHandler()
+      this.disposeHandler = window['viewer'].layerManager.layersChanged.add(() => this.layerChangedHandler())
+      window['viewer'].registerDisposer(this.disposeHandler)
+    })
+  }
+
+  ngOnDestroy(){
+    this.disposeHandler()
+    this.subscription.unsubscribe()
+  }
+
+  layerChangedHandler(){
+    console.log('handle layer change',window['viewer'].layerManager.managedLayers)
+
+    this.ngLayers = (window['viewer'].layerManager.managedLayers as any[]).map(obj => ({
+      name : obj.name,
+      type : obj.initialSpecification.type,
+      source : obj.sourceUrl,
+      visible : obj.visible
+    }) as NgLayerInterface)
+    
+  }
+
   public muteClass(layer:AtlasViewerLayerInterface):boolean{
     if(this.layers.length === 0)
       return false
@@ -18,4 +60,19 @@ export class LayerBrowser{
       ? this.layers.some(l => l.type === 'nonmixable')
       : false
   }
-}
\ No newline at end of file
+
+  public classVisible(layer:NgLayerInterface):boolean{
+    return typeof layer.visible === 'undefined'
+      ? true
+      : layer.visible
+  }
+}
+
+interface NgLayerInterface{
+  name : string
+  visible : boolean
+  source : string
+  type : string // image | segmentation | etc ...
+  transform? : [[number, number, number, number],[number, number, number, number],[number, number, number, number],[number, number, number, number]] | null
+  // colormap : string
+}
diff --git a/src/ui/layerbrowser/layerbrowser.template.html b/src/ui/layerbrowser/layerbrowser.template.html
index d98b3f89d..26c068997 100644
--- a/src/ui/layerbrowser/layerbrowser.template.html
+++ b/src/ui/layerbrowser/layerbrowser.template.html
@@ -1,5 +1,18 @@
 <div container>
   <panel-component
+    [ngClass] = "{'muted' : !classVisible(ngLayer)}"
+    class = "layerContainer"
+    *ngFor = "let ngLayer of ngLayers">
+
+    <div heading>
+      {{ ngLayer.name }} : {{ ngLayer.type }}
+    </div>
+
+    <div body>
+      {{ ngLayer.source }}
+    </div>
+  </panel-component>
+  <!-- <panel-component
     [ngClass] = "{'muted' : muteClass(layer)}"
     class = "layerContainer"
     *ngFor = "let layer of layers">
@@ -10,5 +23,5 @@
     <div body>
       {{ layer.url }}
     </div>
-  </panel-component>
+  </panel-component> -->
 </div>
\ No newline at end of file
diff --git a/src/ui/nehubaContainer/nehubaContainer.component.ts b/src/ui/nehubaContainer/nehubaContainer.component.ts
index dfaff17a3..8c955e73b 100644
--- a/src/ui/nehubaContainer/nehubaContainer.component.ts
+++ b/src/ui/nehubaContainer/nehubaContainer.component.ts
@@ -30,7 +30,7 @@ export class NehubaContainer implements OnInit, OnDestroy{
   private newViewer$ : Observable<any>
   private selectedParcellation$ : Observable<any>
   private selectedRegions$ : Observable<any[]>
-  private dedicatedView$ : Observable<string|null>
+  private dedicatedView$ : Observable<string[]|null>
   private fetchedSpatialDatasets$ : Observable<any[]>
   private userLandmarks$ : Observable<UserLandmark[]>
   public onHoverSegmentName$ : Observable<string>
@@ -316,6 +316,7 @@ export class NehubaContainer implements OnInit, OnDestroy{
         if(newLayers.length > 0){
           const newLayersObj:any = {}
           newLayers.forEach(obj => newLayersObj[obj.name] = obj)
+          debugger
           this.nehubaViewer.loadLayer(newLayersObj)
           this.ngLayersRegister.layers = this.ngLayersRegister.layers.concat(newLayers)
         }
@@ -356,14 +357,13 @@ export class NehubaContainer implements OnInit, OnDestroy{
 
       /* TODO abit hacky. test what happens when: select dedicated view, then change template... check ngLayerRegister */
       if(dedicatedView){
-        const dedicatedViewLayer = {
-          name : 'niftiViewer',
-          source : dedicatedView,
-          visible: true,
+        this.ngLayersRegister.layers = this.ngLayersRegister.layers.concat(dedicatedView.map((layer, index) => ({
+          name : `dedicatedview-${index}`,
+          source : layer,
+          visible : true,
           mixability : 'nonmixable',
-          transform:null
-        }
-        this.ngLayersRegister.layers.push(dedicatedViewLayer)
+          transform : null
+        })))
       }
     })
 
@@ -418,17 +418,18 @@ export class NehubaContainer implements OnInit, OnDestroy{
     this.selectedParcellation = parcellation
   }
 
-  private handleDedicatedView(dedicatedView:string){
-    this.handleNifti(dedicatedView)
-  }
-
-  private handleNifti(url:string|null){
+  private handleDedicatedView(dedicatedView:string[]){
     if(!this.nehubaViewer || !this.nehubaViewer.nehubaViewer){
       /* if nehubaviewer has not yet been initialised for one reason or another, return */
       console.warn('handling nifti view, nehubaviewer has not yet been initialised.')
       return
     }
-    if(url === null){
+
+    /* for now */
+    return
+    if(dedicatedView.length === 0){
+
+      /* remove ng layer (?) */
       this.store.dispatch({
         type : REMOVE_NG_LAYER,
         layer : {
@@ -459,8 +460,8 @@ export class NehubaContainer implements OnInit, OnDestroy{
       this.store.dispatch({
         type : ADD_NG_LAYER,
         layer : {
-          name : 'niftiViewer',
-          source : url,
+          name : null,
+          source : dedicatedView,
           mixability : 'nonmixable',
           shader : getActiveColorMapFragmentMain()
         }
diff --git a/src/ui/nehubaContainer/nehubaViewer/nehubaViewer.component.ts b/src/ui/nehubaContainer/nehubaViewer/nehubaViewer.component.ts
index 98c5cdea9..82d79e510 100644
--- a/src/ui/nehubaContainer/nehubaViewer/nehubaViewer.component.ts
+++ b/src/ui/nehubaContainer/nehubaViewer/nehubaViewer.component.ts
@@ -20,7 +20,7 @@ export class NehubaViewerUnit implements AfterViewInit,OnDestroy{
   /* only used to set initial navigation state */
   initNav : any
   initRegions : any[]
-  initDedicatedView : string
+  initDedicatedView : string[]
 
   config : any
   
@@ -327,13 +327,17 @@ export class NehubaViewerUnit implements AfterViewInit,OnDestroy{
 
     if(this.initDedicatedView){
       this.hideAllSeg()
-      this.loadLayer({
-        niftiViewer : {
+      const _ = {}
+      
+      this.initDedicatedView.forEach((layer,index) => {
+        _[`dedicatedview-${index}`] = {
           type : 'image',
-          source : this.initDedicatedView,
+          source : layer,
           shader : getActiveColorMapFragmentMain()
         }
       })
+      
+      this.loadLayer(_)
     }
 
     this._s8$ = this.nehubaViewer.mouseOver.segment.subscribe(({segment})=>{
-- 
GitLab