chjj / blessed

A high-level terminal interface library for node.js.
Other
11.32k stars 534 forks source link

Scrolling is goofy after overloading List #81

Open etodanik opened 10 years ago

etodanik commented 10 years ago

I created my own widget based on List. The difference is that I'm trying to have a list with boxes that have borders, and are about 4 lines tall.

My list receives objects instead of strings, that contain a "summary" and a "command".

Everything works fine, except for scrolling. Without overloading select, it looks like scrolling is acting as if each item is still only one line tall. I tried to do the following (Copy pasted code for the widget I'm using).

Here's my code:

var blessed = require('blessed');
var Box = blessed.widget.box;

var CommandList = function(){
    blessed.widget.list.apply(this,arguments)
};

CommandList.prototype = blessed.widget.list.prototype;

CommandList.prototype.select = function(index) {
  if (!this.items.length) {
    this.selected = 0;
    this.value = '';
    this.scrollTo(0);
    return;
  }

  if (typeof index === 'object') {
    index = this.items.indexOf(index);
  }

  if (index < 0) index = 0;
  else if (index >= this.items.length) index = this.items.length - 1;

  if (this.selected === index && this._listInitialized) return;
  this._listInitialized = true;

  this.selected = index;
  this.value = this.ritems[this.selected];
  this.setScrollPerc(this.selected * 4);
  this.screen.render();
};

CommandList.prototype.add =
CommandList.prototype.addItem =
CommandList.prototype.appendItem = function(item) {
  var self = this;

  this.ritems.push(item.summary + ' ' + item.command);

  // Note: Could potentially use Button here.
  var options = {
    screen: this.screen,
    content: '{bold}' + item.command + '{/bold}' + '\n' + '{#777777-fg}' + item.summary + '{/#777777-fg}',
    border: {
        type: 'line',
        fg: '#222222'
    },
    align: this.align || 'left',
    top: this.itop + this.items.length * 3,
    left: this.ileft + 1,
    right: this.iright + 1,
    padding: {
        left: 1,
        right: 1,
        top: 0,
        bottom: 0
    },
    tags: this.parseTags,
    height: 4,
    hoverEffects: this.mouse ? this.style.item.hover : null,
    focusEffects: this.mouse ? this.style.item.focus : null,
    autoFocus: false,
    tags: true
  };

  if (this.screen.autoPadding) {
    options.top = this.items.length;
    options.left = 1;
    options.right = 1;
  }

  ['bg', 'fg', 'bold', 'underline',
   'blink', 'inverse', 'invisible'].forEach(function(name) {
    options[name] = function() {
      var attr = self.items[self.selected] === item
        ? self.style.selected[name]
        : self.style.item[name];
      if (typeof attr === 'function') attr = attr(item);
      return attr;
    };
  });

  /* if(self.items[self.selected] && self.items[self.selected].summary != item.summary){
    if(self.items.length + 1 % 2 === 0){
        options.bg = '#333333';
    }
  } */

  var item = new Box(options);

  this.items.push(item);
  this.append(item);

  if (this.items.length === 1) {
    this.select(0);
  }

  if (this.mouse) {
    item.on('click', function(data) {
      if (self.items[self.selected] === item) {
        self.emit('action', item, self.selected);
        self.emit('select', item, self.selected);
        return;
      }
      self.select(item);
      self.screen.render();
    });
  }
};

module.exports = CommandList;

Later on I create my list like so:

var CommandList = require('./list.js');

var list = new CommandList({
  parent: screen,
  top: 'center',
  left: -1,
  right: -1,
  width: '100%',
  top: 0,
  bottom: 1,
  fg: 'white',
  selectedBg: 'green',
  selectedFg: 'black',
  mouse: true,
  scrollbar: {
    bg: 'blue'
  },
  items: [
    {
      command: 'testsdf',
      summary: 'b3fa'
    },
    {
      command: 'ba123aa',
      summary: 'baaa'
    },
    {
      command: 'baappppo',
      summary: 'baaa'
    },
  ]
});
etodanik commented 10 years ago

Does anyone still roam these realms?

etodanik commented 10 years ago

Is this repository alive?

chjj commented 9 years ago

This is sort of non-trivial. You'll have to change some other internal methods for ScrollableBox. It assumes lists are only as tall as the number of items. Lists are hardcoded in a lot of different places because of their complex behavior. There might be an easy way to add this as an option by changing lines like this.lines.length to this.lines.length * lineHeight in the scrolling methods, but I'll have to see how clean that is.