From dc2bfda057013e2a72895a62e02682172039761b Mon Sep 17 00:00:00 2001 From: Christopher Jeffrey Date: Sun, 16 Jun 2013 09:31:55 -0500 Subject: [PATCH] mousemove and mouse refactor. fixes. --- README.md | 6 ++++ lib/program.js | 8 ++++- lib/widget.js | 91 ++++++++++++++++++++++++++++++++++++-------------- test/widget.js | 19 ++++++++--- 4 files changed, 93 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index eb6b17e..03f428f 100644 --- a/README.md +++ b/README.md @@ -202,6 +202,7 @@ The screen on which every other node renders. ##### Events: - inherits all from Node. +- **resize** - received on screen resize. - **mouse** - received on mouse events. - **keypress** - received on key events. - **element [name]** - global events received for all elements. @@ -265,7 +266,12 @@ The base element. ##### Events: - inherits all from Node. +- **blur, focus** - received when an element is focused or unfocused. - **mouse** - received on mouse events for this element. + - **mousedown, mouseup** - mouse button was pressed or released. + - **wheeldown, wheelup** - wheel was scrolled down or up. + - **mouseover, mouseout** - element was hovered or unhovered. + - **mousemove** - mouse was moved somewhere on this element. - **keypress** - received on key events for this element. - **move** - received when the element is moved. - **resize** - received when the element is resized. diff --git a/lib/program.js b/lib/program.js index 385beae..7302256 100644 --- a/lib/program.js +++ b/lib/program.js @@ -252,9 +252,15 @@ Program.prototype._bindMouse = function(s) { // Wrong //if (b > 32 && b < 64) { // delete key.button; - // key.action = 'movement'; + // key.action = 'mousemove'; //} + // Probably a movement. + if (key.action === 'mousedown' && key.button === 'unknown') { + delete key.button; + key.action = 'mousemove'; + } + self.emit('keypress', null, key); self.emit('mouse', key); diff --git a/lib/widget.js b/lib/widget.js index 9855d2d..8b996fb 100644 --- a/lib/widget.js +++ b/lib/widget.js @@ -125,6 +125,7 @@ function Screen(options) { }; //this.focused = null; + this.hover = null; this.history = []; this.clickable = []; this.input = []; @@ -161,15 +162,11 @@ Screen.global = null; Screen.prototype.__proto__ = Node.prototype; // TODO: Bubble events. -Screen.prototype._listenMouse = function(el, hover) { +Screen.prototype._listenMouse = function(el) { var self = this; - if (el) { - if (!hover) { - if (!~this.clickable.indexOf(el)) this.clickable.push(el); - } else { - if (!~this.hover.indexOf(el)) this.hover.push(el); - } + if (el && !~this.clickable.indexOf(el)) { + this.clickable.push(el); } if (this._listenedMouse) return; @@ -186,27 +183,64 @@ Screen.prototype._listenMouse = function(el, hover) { //}); this.program.on('mouse', function(data) { - var i = 0, left, top, el; + var i = 0 + , left + , top + , width + , height + , el + , set + , ret; + for (; i < self.clickable.length; i++) { el = self.clickable[i]; - left = el.left + (el.border ? 1 : 0); - top = el.top + (el.border ? 1 : 0); - if (el.parent.childBase != null) top -= el.parent.childBase; - if (data.x > left && data.x <= left + el.width - && data.y > top && data.y <= top + el.height) { + if (el.hidden) continue; + + // Get the true coordinates. + //ret = el.render(true); + ret = el._lastPos; + if (!ret) continue; + left = ret.xi; + top = ret.yi; + width = ret.xl - ret.xi; + height = ret.yl - ret.yi; + + // left = el.left + (el.border ? 1 : 0); + // top = el.top + (el.border ? 1 : 0); + // if (el.parent.childBase != null) top -= el.parent.childBase; + // width = el.width; + // height = el.height; + + if (data.x > left && data.x <= left + width + && data.y > top && data.y <= top + height) { el.emit('mouse', data); self.emit('element mouse', el, data); if (data.action === 'mouseup') { el.emit('click', data); self.emit('element click', el, data); - } else if (data.action === 'movement') { - el.emit('hover', data); - self.emit('element hover', el, data); + } else if (data.action === 'mousemove') { + if (self.hover !== el && !set) { + if (self.hover) { + self.hover.emit('mouseout', data); + self.emit('element mouseout', self.hover, data); + } + el.emit('mouseover', data); + self.emit('element mouseover', el, data); + self.hover = el; + } + set = true; } el.emit(data.action, data); self.emit('element ' + data.action, data); } } + + if (data.action === 'mousemove' && self.hover && !set) { + self.hover.emit('mouseout', data); + self.emit('element mouseout', self.hover, data); + self.hover = null; + } + self.emit('mouse', data); }); }; @@ -217,10 +251,14 @@ Screen.prototype._listenKeys = function(el) { if (el) { if (!~this.input.indexOf(el)) { - if (this._listenedMouse) { - //this._listenMouse(el); - el.on('click', el.focus.bind(el)); - } + // Listen for click, but do not enable + // mouse if it's not enabled yet. + var lm = this._listenedMouse; + this._listenedMouse = true; + //this._listenMouse(el); + el.on('click', el.focus.bind(el)); + this._listenedMouse = lm; + this.input.push(el); } } @@ -653,7 +691,6 @@ function Element(options) { this.on('newListener', function fn(type) { if (type === 'mouse' || type === 'click' - || type === 'hover' || type === 'mouseover' || type === 'mouseout' || type === 'mousedown' @@ -661,8 +698,7 @@ function Element(options) { || type === 'mousewheel' || type === 'wheeldown' || type === 'wheelup' - || type === 'mousemove' - || type === 'movement') { + || type === 'mousemove') { self.screen._listenMouse(self); } else if (type === 'keypress') { self.screen._listenKeys(self); @@ -804,6 +840,7 @@ Element.prototype.__defineGetter__('bottom', function() { return (this.parent.bottom || 0) + this.position.bottom; }); +// TODO: Move _getShrinkSize calculation here. This will in turn fix .left. Element.prototype.__defineGetter__('width', function() { var width = this.position.width; if (typeof width === 'string') { @@ -825,6 +862,7 @@ Element.prototype.__defineGetter__('width', function() { return width; }); +// TODO: Move _getShrinkSize calculation here. This will in turn fix .top. Element.prototype.__defineGetter__('height', function() { var height = this.position.height; if (typeof height === 'string') { @@ -1041,6 +1079,7 @@ function Box(options) { Box.prototype.__proto__ = Element.prototype; +// TODO: Optimize. Move elsewhere. Box.prototype._getShrinkSize = function(content) { var lines = content.replace(/\x1b\[[\d;]*m/g, '').split('\n'); return { @@ -1054,6 +1093,8 @@ Box.prototype._getShrinkSize = function(content) { }; // Here be dragons. +// TODO: Potentially move all calculations performed on +// xi/xl/yi/yl here to Element offset and size getters. Box.prototype.render = function(stop) { // NOTE: Maybe move this `hidden` check down below `stop` check and return `ret`. if (this.hidden) return; @@ -1140,7 +1181,7 @@ Box.prototype.render = function(stop) { } } - var ret = { + var ret = this._lastPos = { xi: xi_, xl: xl, yi: yi_, @@ -1747,7 +1788,7 @@ Textbox.prototype.render = function(stop) { this.content = this.content.slice(-(this.width - (this.border ? 2 : 0) - 1)); var ret = this._render(stop); this.content = content; - if (stop) return stop; + if (stop) return ret; return ret; }; diff --git a/test/widget.js b/test/widget.js index e855bc5..bbe9c48 100644 --- a/test/widget.js +++ b/test/widget.js @@ -1,9 +1,5 @@ var blessed = require('blessed') - , program = blessed({ tput: true }); - -var screen = new blessed.Screen({ - program: program -}); + , screen = blessed.Screen({ tput: true }); screen.append(new blessed.Text({ top: 0, @@ -176,6 +172,19 @@ screen.on('element focus', function(old, cur) { screen.render(); }); +/* +screen.on('element mouseover', function(el) { + el._bg = el.bg; + el.bg = 1; + screen.render(); +}); + +screen.on('element mouseout', function(el) { + el.bg = el._bg; + screen.render(); +}); +*/ + var input = new blessed.Textbox({ mouse: true, label: ' My Input ',