« get me outta code hell

Path listing - mtui - Music Text User Interface - user-friendly command line music player
about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFlorrie <towerofnix@gmail.com>2018-06-04 10:14:14 -0300
committerFlorrie <towerofnix@gmail.com>2018-06-04 10:14:14 -0300
commit87819e1082d0edc28bbf38eded57ab992083458e (patch)
tree8664c720327d1ec4666189ee30d4f8b21f2d6e94
parent1e6509ff61903b263b8c4afca79e71d659206cf3 (diff)
Path listing
-rw-r--r--todo.txt1
m---------tui-lib0
-rw-r--r--ui.js109
3 files changed, 107 insertions, 3 deletions
diff --git a/todo.txt b/todo.txt
index 42a5058..f682a1a 100644
--- a/todo.txt
+++ b/todo.txt
@@ -1,6 +1,7 @@
 TODO: A way to see the path of the currently selected item in any grouplike
       element. Each item in the path should be a button that, when pressed,
       makes the MAIN grouplike view navigate there.
+      (Done!)
 
 TODO: A "shuffle queue" button!
 
diff --git a/tui-lib b/tui-lib
-Subproject eae9716c237ad7c9602cc05f6babc6c2714e258
+Subproject a3df7cf7205d12ab5e6fc7b5746cae6c4a6a821
diff --git a/ui.js b/ui.js
index 8e235a0..3090873 100644
--- a/ui.js
+++ b/ui.js
@@ -1,6 +1,6 @@
 const { getDownloaderFor } = require('./downloaders')
 const { getPlayer } = require('./players')
-const { parentSymbol, isGroup } = require('./playlist-utils')
+const { parentSymbol, isGroup, isTrack, getItemPath } = require('./playlist-utils')
 const ansi = require('./tui-lib/util/ansi')
 const Button = require('./tui-lib/ui/form/Button')
 const DisplayElement = require('./tui-lib/ui/DisplayElement')
@@ -48,6 +48,21 @@ class AppElement extends FocusElement {
       () => handleSelectFromMain(item)))
     this.grouplikeListingElement.on('queue', item => this.queueGrouplikeItem(item))
 
+    const handleSelectFromPathElement = item => {
+      this.form.curIndex = this.form.inputs.indexOf(this.grouplikeListingElement)
+      this.root.select(this.grouplikeListingElement)
+      if (isGroup(item)) {
+        this.grouplikeListingElement.loadGrouplike(item)
+      } else if (item[parentSymbol]) {
+        this.grouplikeListingElement.loadGrouplike(item[parentSymbol])
+        this.grouplikeListingElement.selectAndShow(item)
+      }
+    }
+
+    this.paneLeft.addChild(this.grouplikeListingElement.pathElement)
+    this.form.addInput(this.grouplikeListingElement.pathElement, false)
+    this.grouplikeListingElement.pathElement.on('select', item => handleSelectFromPathElement(item))
+
     this.queueListingElement = new GrouplikeListingElement(this.recordStore)
     this.queueListingElement.loadGrouplike(this.queueGrouplike)
     this.paneRight.addChild(this.queueListingElement)
@@ -57,6 +72,10 @@ class AppElement extends FocusElement {
     this.queueListingElement.on('select (space)', item => this.handleSpacePressed(
       () => this.playGrouplikeItem(item, false)))
 
+    this.paneRight.addChild(this.queueListingElement.pathElement)
+    this.form.addInput(this.queueListingElement.pathElement, false)
+    this.queueListingElement.pathElement.on('select', item => handleSelectFromPathElement(item))
+
     this.playbackPane = new Pane()
     this.addChild(this.playbackPane)
 
@@ -89,8 +108,16 @@ class AppElement extends FocusElement {
     this.playbackPane.w = this.contentW
     this.playbackPane.h = this.contentH - this.playbackPane.y
 
-    this.grouplikeListingElement.fillParent()
-    this.queueListingElement.fillParent()
+    const fixListingLayout = listing => {
+      listing.fillParent()
+      listing.h--
+      listing.pathElement.y = listing.parent.contentH - 1
+      listing.pathElement.w = listing.parent.contentW
+    }
+
+    fixListingLayout(this.grouplikeListingElement)
+    fixListingLayout(this.queueListingElement)
+
     this.playbackInfoElement.fillParent()
   }
 
@@ -318,6 +345,8 @@ class GrouplikeListingElement extends ListScrollForm {
 
     this.grouplike = null
     this.recordStore = recordStore
+
+    this.pathElement = new PathElement()
   }
 
   keyPressed(keyBuf) {
@@ -409,6 +438,18 @@ class GrouplikeListingElement extends ListScrollForm {
     }
   }
 
+  set curIndex(newIndex) {
+    this._curIndex = newIndex
+
+    if (this.pathElement && this.inputs[this.curIndex]) {
+      this.pathElement.showItem(this.inputs[this.curIndex].item)
+    }
+  }
+
+  get curIndex() {
+    return this._curIndex
+  }
+
   get firstItemIndex() {
     return Math.min(this.inputs.length, 1)
   }
@@ -486,6 +527,68 @@ class GrouplikeItemElement extends Button {
   }
 }
 
+class PathElement extends ListScrollForm {
+  constructor() {
+    super('horizontal')
+    this.captureTab = false
+  }
+
+  showItem(item) {
+    while (this.inputs.length) {
+      this.removeInput(this.inputs[0])
+    }
+
+    if (!isTrack(item) && !isGroup(item)) {
+      return
+    }
+
+    const itemPath = getItemPath(item)
+
+    for (const pathItem of itemPath) {
+      const isLast = pathItem === itemPath[itemPath.length - 1]
+      const element = new PathItemElement(pathItem, isLast)
+      element.on('select', () => this.emit('select', pathItem))
+      element.fixLayout()
+      this.addInput(element)
+    }
+
+    this.curIndex = this.inputs.length - 1
+
+    this.scrollToEnd()
+    this.fixLayout()
+  }
+}
+
+class PathItemElement extends FocusElement {
+  constructor(item, isLast) {
+    super()
+
+    this.item = item
+    this.isLast = isLast
+
+    this.button = new Button(item.name || '(Unnamed)')
+    this.addChild(this.button)
+
+    this.button.on('pressed', () => {
+      this.emit('select')
+    })
+
+    this.arrowLabel = new Label(isLast ? '' : ' > ')
+    this.addChild(this.arrowLabel)
+  }
+
+  focused() {
+    this.root.select(this.button)
+  }
+
+  fixLayout() {
+    this.button.fixLayout()
+    this.arrowLabel.fixLayout()
+    this.w = this.button.w + this.arrowLabel.w
+    this.arrowLabel.x = this.button.right
+  }
+}
+
 class PlaybackInfoElement extends DisplayElement {
   constructor() {
     super()