diff options
-rw-r--r-- | ui.js | 190 |
1 files changed, 95 insertions, 95 deletions
diff --git a/ui.js b/ui.js index 3496d97..038c008 100644 --- a/ui.js +++ b/ui.js @@ -94,6 +94,19 @@ class AppElement extends FocusElement { */ this.menu = new ContextMenu() this.addChild(this.menu) + + this.whereControl = new InlineListPickerElement('Where?', [ + {value: 'next', label: 'After current song'}, + {value: 'end', label: 'At end of queue'}, + {value: 'distribute-evenly', label: 'Distributed across queue evenly'}, + {value: 'distribute-randomly', label: 'Distributed across queue randomly'} + ]) + + this.orderControl = new InlineListPickerElement('Order?', [ + {value: 'shuffle', label: 'Shuffle all'}, + {value: 'shuffle-groups', label: 'Shuffle order of groups'}, + {value: 'normal', label: 'In order'} + ]) } selected() { @@ -107,36 +120,8 @@ class AppElement extends FocusElement { grouplikeListing.on('download', item => this.downloadGrouplikeItem(item)) grouplikeListing.on('browse', item => grouplikeListing.loadGrouplike(item)) - grouplikeListing.on('menu', (item, opts) => this.menu.show(opts)) - - grouplikeListing.on('queue', (item, {where = 'end', order = 'normal', play = false} = {}) => { - if (isGroup(item)) { - if (order === 'shuffle') { - item = {items: shuffleArray(flattenGrouplike(item).items)} - } else if (order === 'shuffle-groups') { - item = shuffleOrderOfGroups(item) - } - } - - if (where === 'next' || where === 'end') { - let afterItem = null - if (where === 'next') { - afterItem = this.playingTrack - } - - this.queueGrouplikeItem(item, afterItem, { - movePlayingTrack: order === 'normal' - }) - } else if (where.startsWith('distribute-')) { - this.distributeQueueGrouplikeItem(item, where.slice('distribute-'.length)) - } - - if (play) { - this.playGrouplikeItem(item) - } - }) - - grouplikeListing.on('unqueue', item => this.unqueueGrouplikeItem(item)) + grouplikeListing.on('menu', (item, el) => this.showMenuForItemElement(el)) + grouplikeListing.on('queue', (item, opts) => this.handleQueueOptions(item, opts)) const updateListingsFor = item => { for (const grouplikeListing of this.tabber.tabberElements) { @@ -241,7 +226,54 @@ class AppElement extends FocusElement { } grouplikeListing.pathElement.on('select', item => handleSelectFromPathElement(item)) + } + + showMenuForItemElement(el) { + const emitControls = play => () => { + this.handleQueueOptions(item, { + where: this.whereControl.curValue, + order: this.orderControl.curValue, + play: play + }) + } + + const { item, isGroup, isMarked } = el + const { editMode } = this + const anyMarked = editMode && this.markGrouplike.items.length > 0 + this.menu.show({ + x: el.absLeft, + y: el.absTop + 1, + items: [ + // A label that just shows some brief information about the item. + isGroup && {label: + `("${item.name}" -` + + ` ${item.items.length} item${item.items.length === 1 ? '' : 's'}` + + `, ${countTotalItems(item)} total` + + ')'}, + + // The actual controls! + {divider: true}, + // TODO: Don't emit these on the element (and hence receive them from + // the listing) - instead, handle their behavior directly. We'll want + // to move the "mark"/"paste" (etc) code into separate functions, + // instead of just defining their behavior inside the listing event + // handlers. + editMode && {label: isMarked ? 'Unmark' : 'Mark', action: () => el.emit('mark')}, + anyMarked && {label: 'Paste (above)', action: () => el.emit('paste', {where: 'above'})}, + anyMarked && {label: 'Paste (below)', action: () => el.emit('paste', {where: 'below'})}, + // anyMarked && !this.isReal && {label: 'Paste', action: () => this.emit('paste')}, // No "above" or "elow" in the label because the "fake" item/row will be replaced (it'll disappear, since there'll be an item in the group) + editMode && {divider: true}, + + {element: this.whereControl}, + {element: this.orderControl}, + {label: 'Play!', action: emitControls(true)}, + {label: 'Queue!', action: emitControls(false)}, + {divider: true}, + + {label: 'Remove from queue', action: () => this.unqueueGrouplikeItem(item)} + ] + }) } async handlePlaylistSource(source, newTab = false) { @@ -450,7 +482,37 @@ class AppElement extends FocusElement { this.player.kill() } - async queueGrouplikeItem(topItem, afterItem = null, {movePlayingTrack = true} = {}) { + // TODO: I'd like to name/incorporate this function better.. for now it's + // just directly moved from the old event listener on grouplikeListings for + // 'queue'. + handleQueueOptions(item, {where = 'end', order = 'normal', play = false} = {}) { + if (isGroup(item)) { + if (order === 'shuffle') { + item = {items: shuffleArray(flattenGrouplike(item).items)} + } else if (order === 'shuffle-groups') { + item = shuffleOrderOfGroups(item) + } + } + + if (where === 'next' || where === 'end') { + let afterItem = null + if (where === 'next') { + afterItem = this.playingTrack + } + + this.queueGrouplikeItem(item, afterItem, { + movePlayingTrack: order === 'normal' + }) + } else if (where.startsWith('distribute-')) { + this.distributeQueueGrouplikeItem(item, where.slice('distribute-'.length)) + } + + if (play) { + this.playGrouplikeItem(item) + } + } + + queueGrouplikeItem(topItem, afterItem = null, {movePlayingTrack = true} = {}) { const newTrackIndex = this.queueGrouplike.items.length // The position which new tracks should be added at, if afterItem is @@ -1236,19 +1298,6 @@ class InteractiveGrouplikeItemElement extends BasicGrouplikeItemElement { super(item.name) this.item = item this.recordStore = recordStore - - this.whereControl = new InlineListPickerElement('Where?', [ - {value: 'next', label: 'After current song'}, - {value: 'end', label: 'At end of queue'}, - {value: 'distribute-evenly', label: 'Distributed across queue evenly'}, - {value: 'distribute-randomly', label: 'Distributed across queue randomly'} - ]) - - this.orderControl = new InlineListPickerElement('Order?', [ - {value: 'shuffle', label: 'Shuffle all'}, - {value: 'shuffle-groups', label: 'Shuffle order of groups'}, - {value: 'normal', label: 'In order'} - ]) } drawTo(writable) { @@ -1272,7 +1321,7 @@ class InteractiveGrouplikeItemElement extends BasicGrouplikeItemElement { } else if (telc.isCaselessLetter(keyBuf, 'x')) { this.emit('remove') } else if (telc.isCaselessLetter(keyBuf, 'm') || telc.isCaselessLetter(keyBuf, 'f')) { - this.showMenu() + this.emit('menu', this) } } @@ -1290,60 +1339,11 @@ class InteractiveGrouplikeItemElement extends BasicGrouplikeItemElement { return false } else if (button === 'right') { this.parent.selectInput(this) - this.showMenu() + this.emit('menu', this) return false } } - showMenu() { - const editMode = this.recordStore.app.editMode - const anyMarked = editMode && !!this.recordStore.app.markGrouplike.items.length - this.emit('menu', { - x: this.absLeft, - y: this.absTop + 1, - items: [ - // A label that just shows some brief information about the item. - this.isGroup && {label: - `("${this.item.name}" -` + - ` ${this.item.items.length} item${this.item.items.length === 1 ? '' : 's'}` + - `, ${countTotalItems(this.item)} total` + - ')'}, - - // The actual controls! - {divider: true}, - editMode && {label: this.isMarked ? 'Unmark' : 'Mark', action: () => this.emit('mark')}, - anyMarked && {label: 'Paste (above)', action: () => this.emit('paste', {where: 'above'})}, - anyMarked && {label: 'Paste (below)', action: () => this.emit('paste', {where: 'below'})}, - // anyMarked && !this.isReal && {label: 'Paste', action: () => this.emit('paste')}, // No "above" or "elow" in the label because the "fake" item/row will be replaced (it'll disappear, since there'll be an item in the group) - editMode && {divider: true}, - - {element: this.whereControl}, - {element: this.orderControl}, - {label: 'Play!', action: () => this.playWithControls()}, - {label: 'Queue!', action: () => this.queueWithControls()}, - {divider: true}, - - {label: 'Remove from queue', action: () => this.emit('unqueue')} - ] - }) - } - - playWithControls() { - this.emitControls(true) - } - - queueWithControls() { - this.emitControls(false) - } - - emitControls(play) { - this.emit('queue', { - where: this.whereControl.curValue, - order: this.orderControl.curValue, - play: play - }) - } - writeStatus(writable) { if (this.isGroup) { // The ANSI attributes here will apply to the rest of the line, too. |