Mon 21 Jul 22:43:21 CEST 2025
This commit is contained in:
parent
71cbc791a7
commit
41a6dec074
441
js/term/widgets/listbar.js
Normal file
441
js/term/widgets/listbar.js
Normal file
|
@ -0,0 +1,441 @@
|
|||
/**
|
||||
** ==============================
|
||||
** O O O OOOO
|
||||
** O O O O O O
|
||||
** O O O O O O
|
||||
** OOOO OOOO O OOO OOOO
|
||||
** O O O O O O O
|
||||
** O O O O O O O
|
||||
** OOOO OOOO O O OOOO
|
||||
** ==============================
|
||||
** Dr. Stefan Bosse http://www.bsslab.de
|
||||
**
|
||||
** COPYRIGHT: THIS SOFTWARE, EXECUTABLE AND SOURCE CODE IS OWNED
|
||||
** BY THE AUTHOR(S).
|
||||
** THIS SOURCE CODE MAY NOT BE COPIED, EXTRACTED,
|
||||
** MODIFIED, OR OTHERWISE USED IN A CONTEXT
|
||||
** OUTSIDE OF THE SOFTWARE SYSTEM.
|
||||
**
|
||||
** $AUTHORS: Christopher Jeffrey and contributors, Stefan Bosse
|
||||
** $INITIAL: (C) 2013-2016, Christopher Jeffrey and contributors
|
||||
** $CREATED: sbosse on 28-3-15.
|
||||
** $VERSION: 1.2.2
|
||||
**
|
||||
** $INFO:
|
||||
*
|
||||
* listbar.js - listbar element for blessed
|
||||
*
|
||||
** $ENDOFINFO
|
||||
*/
|
||||
/**
|
||||
* Modules
|
||||
*/
|
||||
var Comp = Require('com/compat');
|
||||
|
||||
var helpers = Require('term/helpers');
|
||||
|
||||
var Node = Require('term/widgets/node');
|
||||
var Box = Require('term/widgets/box');
|
||||
|
||||
/**
|
||||
* Listbar / HorizontalList
|
||||
*/
|
||||
|
||||
function Listbar(options) {
|
||||
var self = this;
|
||||
|
||||
if (!instanceOf(this,Node)) {
|
||||
return new Listbar(options);
|
||||
}
|
||||
|
||||
options = options || {};
|
||||
|
||||
this.items = [];
|
||||
this.ritems = [];
|
||||
this.commands = [];
|
||||
|
||||
this.leftBase = 0;
|
||||
this.leftOffset = 0;
|
||||
|
||||
this.mouse = options.mouse || false;
|
||||
|
||||
Box.call(this, options);
|
||||
|
||||
if (!this.style.selected) {
|
||||
this.style.selected = {};
|
||||
}
|
||||
|
||||
if (!this.style.item) {
|
||||
this.style.item = {};
|
||||
}
|
||||
|
||||
if (options.commands || options.items) {
|
||||
this.setItems(options.commands || options.items);
|
||||
}
|
||||
|
||||
if (options.keys) {
|
||||
this.on('keypress', function(ch, key) {
|
||||
if (key.name === 'left'
|
||||
|| (options.vi && key.name === 'h')
|
||||
|| (key.shift && key.name === 'tab')) {
|
||||
self.moveLeft();
|
||||
self.screen.render();
|
||||
// Stop propagation if we're in a form.
|
||||
if (key.name === 'tab') return false;
|
||||
return;
|
||||
}
|
||||
if (key.name === 'right'
|
||||
|| (options.vi && key.name === 'l')
|
||||
|| key.name === 'tab') {
|
||||
self.moveRight();
|
||||
self.screen.render();
|
||||
// Stop propagation if we're in a form.
|
||||
if (key.name === 'tab') return false;
|
||||
return;
|
||||
}
|
||||
if (key.name === 'enter'
|
||||
|| (options.vi && key.name === 'k' && !key.shift)) {
|
||||
self.emit('action', self.items[self.selected], self.selected);
|
||||
self.emit('select', self.items[self.selected], self.selected);
|
||||
var item = self.items[self.selected];
|
||||
if (item._.cmd.callback) {
|
||||
item._.cmd.callback();
|
||||
}
|
||||
self.screen.render();
|
||||
return;
|
||||
}
|
||||
if (key.name === 'escape' || (options.vi && key.name === 'q')) {
|
||||
self.emit('action');
|
||||
self.emit('cancel');
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (options.autoCommandKeys) {
|
||||
this.onScreenEvent('keypress', function(ch) {
|
||||
if (/^[0-9]$/.test(ch)) {
|
||||
var i = +ch - 1;
|
||||
if (!~i) i = 9;
|
||||
return self.selectTab(i);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.on('focus', function() {
|
||||
self.select(self.selected);
|
||||
});
|
||||
}
|
||||
|
||||
//Listbar.prototype.__proto__ = Box.prototype;
|
||||
inheritPrototype(Listbar,Box);
|
||||
|
||||
Listbar.prototype.type = 'listbar';
|
||||
|
||||
Object.defineProperty(Listbar.prototype,'selected',{
|
||||
get: function () {return this.leftBase + this.leftOffset;}
|
||||
});
|
||||
/* Depricated
|
||||
Listbar.prototype.__defineGetter__('selected', function() {
|
||||
return this.leftBase + this.leftOffset;
|
||||
});
|
||||
*/
|
||||
|
||||
Listbar.prototype.setItems = function(commands) {
|
||||
var self = this;
|
||||
|
||||
if (!Array.isArray(commands)) {
|
||||
commands = Object.keys(commands).reduce(function(obj, key, i) {
|
||||
var cmd = commands[key]
|
||||
, cb;
|
||||
|
||||
if (typeof cmd === 'function') {
|
||||
cb = cmd;
|
||||
cmd = { callback: cb };
|
||||
}
|
||||
|
||||
if (cmd.text == null) cmd.text = key;
|
||||
if (cmd.prefix == null) cmd.prefix = ++i + '';
|
||||
|
||||
if (cmd.text == null && cmd.callback) {
|
||||
cmd.text = cmd.callback.name;
|
||||
}
|
||||
|
||||
obj.push(cmd);
|
||||
|
||||
return obj;
|
||||
}, []);
|
||||
}
|
||||
|
||||
this.items.forEach(function(el) {
|
||||
el.detach();
|
||||
});
|
||||
|
||||
this.items = [];
|
||||
this.ritems = [];
|
||||
this.commands = [];
|
||||
|
||||
commands.forEach(function(cmd) {
|
||||
self.add(cmd);
|
||||
});
|
||||
|
||||
this.emit('set items');
|
||||
};
|
||||
|
||||
Listbar.prototype.add =
|
||||
Listbar.prototype.addItem =
|
||||
Listbar.prototype.appendItem = function(item, callback) {
|
||||
var self = this
|
||||
, prev = this.items[this.items.length - 1]
|
||||
, drawn
|
||||
, cmd
|
||||
, title
|
||||
, len;
|
||||
|
||||
if (!this.parent) {
|
||||
drawn = 0;
|
||||
} else {
|
||||
drawn = prev ? prev.aleft + prev.width : 0;
|
||||
if (!this.screen.autoPadding) {
|
||||
drawn += this.ileft;
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof item === 'object') {
|
||||
cmd = item;
|
||||
if (cmd.prefix == null) cmd.prefix = (this.items.length + 1) + '';
|
||||
}
|
||||
|
||||
if (typeof item === 'string') {
|
||||
cmd = {
|
||||
prefix: (this.items.length + 1) + '',
|
||||
text: item,
|
||||
callback: callback
|
||||
};
|
||||
}
|
||||
|
||||
if (typeof item === 'function') {
|
||||
cmd = {
|
||||
prefix: (this.items.length + 1) + '',
|
||||
text: item.name,
|
||||
callback: item
|
||||
};
|
||||
}
|
||||
|
||||
if (cmd.keys && cmd.keys[0]) {
|
||||
cmd.prefix = cmd.keys[0];
|
||||
}
|
||||
|
||||
var t = helpers.generateTags(this.style.prefix || { fg: 'lightblack' });
|
||||
|
||||
title = (cmd.prefix != null ? t.open + cmd.prefix + t.close + ':' : '') + cmd.text;
|
||||
|
||||
len = ((cmd.prefix != null ? cmd.prefix + ':' : '') + cmd.text).length;
|
||||
|
||||
var options = {
|
||||
screen: this.screen,
|
||||
top: 0,
|
||||
left: drawn + 1,
|
||||
height: 1,
|
||||
content: title,
|
||||
width: len + 2,
|
||||
align: 'center',
|
||||
autoFocus: false,
|
||||
tags: true,
|
||||
mouse: true,
|
||||
style: helpers.merge({}, this.style.item),
|
||||
noOverflow: true
|
||||
};
|
||||
|
||||
if (!this.screen.autoPadding) {
|
||||
options.top += this.itop;
|
||||
options.left += this.ileft;
|
||||
}
|
||||
|
||||
['bg', 'fg', 'bold', 'underline',
|
||||
'blink', 'inverse', 'invisible'].forEach(function(name) {
|
||||
options.style[name] = function() {
|
||||
var attr = self.items[self.selected] === el
|
||||
? self.style.selected[name]
|
||||
: self.style.item[name];
|
||||
if (typeof attr === 'function') attr = attr(el);
|
||||
return attr;
|
||||
};
|
||||
});
|
||||
|
||||
var el = new Box(options);
|
||||
|
||||
this._[cmd.text] = el;
|
||||
cmd.element = el;
|
||||
el._.cmd = cmd;
|
||||
|
||||
this.ritems.push(cmd.text);
|
||||
this.items.push(el);
|
||||
this.commands.push(cmd);
|
||||
this.append(el);
|
||||
|
||||
if (cmd.callback) {
|
||||
if (cmd.keys) {
|
||||
this.screen.key(cmd.keys, function() {
|
||||
self.emit('action', el, self.selected);
|
||||
self.emit('select', el, self.selected);
|
||||
if (el._.cmd.callback) {
|
||||
el._.cmd.callback();
|
||||
}
|
||||
self.select(el);
|
||||
self.screen.render();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (this.items.length === 1) {
|
||||
this.select(0);
|
||||
}
|
||||
|
||||
// XXX May be affected by new element.options.mouse option.
|
||||
if (this.mouse) {
|
||||
el.on('click', function() {
|
||||
self.emit('action', el, self.selected);
|
||||
self.emit('select', el, self.selected);
|
||||
if (el._.cmd.callback) {
|
||||
el._.cmd.callback();
|
||||
}
|
||||
self.select(el);
|
||||
self.screen.render();
|
||||
});
|
||||
}
|
||||
|
||||
this.emit('add item');
|
||||
};
|
||||
|
||||
Listbar.prototype.render = function() {
|
||||
var self = this
|
||||
, drawn = 0;
|
||||
|
||||
if (!this.screen.autoPadding) {
|
||||
drawn += this.ileft;
|
||||
}
|
||||
|
||||
this.items.forEach(function(el, i) {
|
||||
if (i < self.leftBase) {
|
||||
el.hide();
|
||||
} else {
|
||||
el.rleft = drawn + 1;
|
||||
drawn += el.width + 2;
|
||||
el.show();
|
||||
}
|
||||
});
|
||||
|
||||
return this._render();
|
||||
};
|
||||
|
||||
Listbar.prototype.select = function(offset) {
|
||||
if (typeof offset !== 'number') {
|
||||
offset = this.items.indexOf(offset);
|
||||
}
|
||||
|
||||
if (offset < 0) {
|
||||
offset = 0;
|
||||
} else if (offset >= this.items.length) {
|
||||
offset = this.items.length - 1;
|
||||
}
|
||||
|
||||
if (!this.parent) {
|
||||
this.emit('select item', this.items[offset], offset);
|
||||
return;
|
||||
}
|
||||
|
||||
var lpos = this._getCoords();
|
||||
if (!lpos) return;
|
||||
|
||||
var self = this
|
||||
, width = (lpos.xl - lpos.xi) - this.iwidth
|
||||
, drawn = 0
|
||||
, visible = 0
|
||||
, el;
|
||||
|
||||
el = this.items[offset];
|
||||
if (!el) return;
|
||||
|
||||
this.items.forEach(function(el, i) {
|
||||
if (i < self.leftBase) return;
|
||||
|
||||
var lpos = el._getCoords();
|
||||
if (!lpos) return;
|
||||
|
||||
if (lpos.xl - lpos.xi <= 0) return;
|
||||
|
||||
drawn += (lpos.xl - lpos.xi) + 2;
|
||||
|
||||
if (drawn <= width) visible++;
|
||||
});
|
||||
|
||||
var diff = offset - (this.leftBase + this.leftOffset);
|
||||
if (offset > this.leftBase + this.leftOffset) {
|
||||
if (offset > this.leftBase + visible - 1) {
|
||||
this.leftOffset = 0;
|
||||
this.leftBase = offset;
|
||||
} else {
|
||||
this.leftOffset += diff;
|
||||
}
|
||||
} else if (offset < this.leftBase + this.leftOffset) {
|
||||
diff = -diff;
|
||||
if (offset < this.leftBase) {
|
||||
this.leftOffset = 0;
|
||||
this.leftBase = offset;
|
||||
} else {
|
||||
this.leftOffset -= diff;
|
||||
}
|
||||
}
|
||||
|
||||
// XXX Move `action` and `select` events here.
|
||||
this.emit('select item', el, offset);
|
||||
};
|
||||
|
||||
Listbar.prototype.removeItem = function(child) {
|
||||
var i = typeof child !== 'number'
|
||||
? this.items.indexOf(child)
|
||||
: child;
|
||||
|
||||
if (~i && this.items[i]) {
|
||||
child = this.items.splice(i, 1)[0];
|
||||
this.ritems.splice(i, 1);
|
||||
this.commands.splice(i, 1);
|
||||
this.remove(child);
|
||||
if (i === this.selected) {
|
||||
this.select(i - 1);
|
||||
}
|
||||
}
|
||||
|
||||
this.emit('remove item');
|
||||
};
|
||||
|
||||
Listbar.prototype.move = function(offset) {
|
||||
this.select(this.selected + offset);
|
||||
};
|
||||
|
||||
Listbar.prototype.moveLeft = function(offset) {
|
||||
this.move(-(offset || 1));
|
||||
};
|
||||
|
||||
Listbar.prototype.moveRight = function(offset) {
|
||||
this.move(offset || 1);
|
||||
};
|
||||
|
||||
Listbar.prototype.selectTab = function(index) {
|
||||
var item = this.items[index];
|
||||
if (item) {
|
||||
if (item._.cmd.callback) {
|
||||
item._.cmd.callback();
|
||||
}
|
||||
this.select(index);
|
||||
this.screen.render();
|
||||
}
|
||||
this.emit('select tab', item, index);
|
||||
};
|
||||
|
||||
/**
|
||||
* Expose
|
||||
*/
|
||||
|
||||
module.exports = Listbar;
|
Loading…
Reference in New Issue
Block a user