From 7a4e4aa8afb341ba3e2b949f71b6c2a05f743831 Mon Sep 17 00:00:00 2001 From: Florrie Date: Sat, 8 Dec 2018 02:38:04 -0400 Subject: Mouse support 'Cuz hey, why not? --- index.js | 2 ++ tui-lib | 2 +- ui.js | 77 ++++++++++++++++++++++++++++++++++++++++++++++++---------------- 3 files changed, 61 insertions(+), 20 deletions(-) diff --git a/index.js b/index.js index d6dbcee..15392bd 100755 --- a/index.js +++ b/index.js @@ -67,6 +67,8 @@ async function main() { root.h = size.height root.fixAllLayout() + process.stdout.write(ansi.startTrackingMouse()) + const flushable = new Flushable(process.stdout, true) flushable.resizeScreen(size) flushable.shouldShowCompressionStatistics = process.argv.includes('--show-ansi-stats') diff --git a/tui-lib b/tui-lib index ab193ed..1f434c1 160000 --- a/tui-lib +++ b/tui-lib @@ -1 +1 @@ -Subproject commit ab193ed3fe91078551c0020e681a191e7b26a122 +Subproject commit 1f434c1ef11fa55bab1718ea4e3ca8d115c0dfb1 diff --git a/ui.js b/ui.js index 2fdbaed..1a64253 100644 --- a/ui.js +++ b/ui.js @@ -781,6 +781,13 @@ class GrouplikeListingElement extends Form { this.root.select(this.form) } + clicked(button) { + if (button === 'left') { + this.selected() + return false + } + } + get selectable() { return this.form.selectable } @@ -1055,27 +1062,50 @@ class InteractiveGrouplikeItemElement extends BasicGrouplikeItemElement { } else if (telc.isCaselessLetter(keyBuf, 'x')) { this.emit('remove') } else if (telc.isCaselessLetter(keyBuf, 'm') || telc.isCaselessLetter(keyBuf, 'f')) { - 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: [ - 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) - {label: 'Play', action: () => this.emit('queue', {where: 'next', play: true})}, - {label: 'Play next', action: () => this.emit('queue', {where: 'next'})}, - {label: 'Play at end', action: () => this.emit('queue', {where: 'end'})}, - this.isGroup && {label: 'Play next, shuffled', action: () => this.emit('queue', {where: 'next', shuffle: true})}, - this.isGroup && {label: 'Play at end, shuffled', action: () => this.emit('queue', {where: 'end', shuffle: true})}, - {label: 'Remove from queue', action: () => this.emit('unqueue')} - ] - }) + this.showMenu() } } + clicked(button) { + if (button === 'left') { + if (this.isSelected) { + if (this.isGroup) { + this.emit('browse') + } else { + this.emit('queue', {where: 'next', play: true}) + } + } else { + this.parent.selectInput(this) + } + return false + } else if (button === 'right') { + this.parent.selectInput(this) + this.showMenu() + 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: [ + 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) + {label: 'Play', action: () => this.emit('queue', {where: 'next', play: true})}, + {label: 'Play next', action: () => this.emit('queue', {where: 'next'})}, + {label: 'Play at end', action: () => this.emit('queue', {where: 'end'})}, + this.isGroup && {label: 'Play next, shuffled', action: () => this.emit('queue', {where: 'next', shuffle: true})}, + this.isGroup && {label: 'Play at end, shuffled', action: () => this.emit('queue', {where: 'end', shuffle: true})}, + {label: 'Remove from queue', action: () => this.emit('unqueue')} + ] + }) + } + writeStatus(writable) { if (this.isGroup) { // The ANSI attributes here will apply to the rest of the line, too. @@ -1164,7 +1194,10 @@ class ListingJumpElement extends Form { class PathElement extends ListScrollForm { constructor() { - super('horizontal') + // TODO: Once we've got the horizontal scrollbar draw working, perhaps + // enable this? Well probably not. This is more a TODO to just, well, + // implement that horizontal scrollbar drawing anyway. + super('horizontal', false) this.captureTab = false } @@ -1217,6 +1250,12 @@ class PathItemElement extends FocusElement { this.root.select(this.button) } + clicked(button) { + if (button === 'left') { + this.emit('select') + } + } + fixLayout() { this.button.fixLayout() this.arrowLabel.fixLayout() -- cgit 1.3.0-6-gf8a5