cleanup and refinement of ribbon pan handler (still not too happy with it)...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2016-05-16 00:56:15 +03:00
parent e8c59924e9
commit 856d212aed
4 changed files with 142 additions and 47 deletions

View File

@ -500,6 +500,11 @@ module.StatusBar = core.ImageGridFeatures.Feature({
} }
}], }],
['ribbonPanning.post',
function(_, gid){
gid == this.data.getRibbon() && this.updateStatusBar()
}],
// Workspace... // Workspace...
['saveWorkspace', ['saveWorkspace',
core.makeWorkspaceConfigWriter( core.makeWorkspaceConfigWriter(

View File

@ -1800,8 +1800,25 @@ var ControlActions = actions.Actions({
'focus-central-image': 'silent', 'focus-central-image': 'silent',
'ribbon-pan-threshold': 30, 'ribbon-pan-threshold': 30,
'control-in-progress-timeout': 100,
}, },
// Ribbon pan "event"...
//
// Protocol:
// - pre phase is called when pan is started.
// - post phase is called when pan is finished.
//
// This is not intended to be called by user, instead it is
// internally called by the pan handler.
//
// NOTE: more than one ribbon can be panned at once.
ribbonPanning: ['- Interface/',
core.notUserCallable(function(gid){
// This is ribbon pan event...
//
// Not for direct use.
})],
// XXX this is really slow on IE... // XXX this is really slow on IE...
toggleRibbonPanHandling: ['Interface/Toggle ribbon pan handling', toggleRibbonPanHandling: ['Interface/Toggle ribbon pan handling',
@ -1817,6 +1834,9 @@ var ControlActions = actions.Actions({
// XXX // XXX
var that = this var that = this
var r = this.ribbons.getRibbon(target) var r = this.ribbons.getRibbon(target)
var rgid = this.ribbons.getElemGID(r)
var data = false
var post_handlers
// setup dragging... // setup dragging...
if(r.length > 0 && !r.hasClass('draggable')){ if(r.length > 0 && !r.hasClass('draggable')){
@ -1835,17 +1855,16 @@ var ControlActions = actions.Actions({
//evt.stopPropagation() //evt.stopPropagation()
// XXX stop all previous animations... // XXX stop all previous animations...
//r.velocity("stop") r.velocity("stop")
var d = that.ribbons.dom var d = that.ribbons.dom
var s = that.scale
var g = evt.gesture var g = evt.gesture
var s = that.scale
var data = r.data('drag-data')
// we just started... // we just started...
if(!data){ if(!data){
that.__control_in_progress = (that.__control_in_progress || 0) + 1 that.__control_in_progress = (that.__control_in_progress || 0) + 1
post_handlers = that.ribbonPanning.pre(that, [rgid])
// hide and remove current image indicator... // hide and remove current image indicator...
// NOTE: it will be reconstructed on // NOTE: it will be reconstructed on
@ -1860,20 +1879,21 @@ var ControlActions = actions.Actions({
}) })
// store initial position... // store initial position...
var data = { data = {
left: d.getOffset(this).left, //left: d.getOffset(this).left,
left: $(this).transform('x'),
pointers: g.pointers.length, pointers: g.pointers.length,
} }
r.data('drag-data', data)
} }
// do the actual move... // do the actual move...
d.setOffset(this, data.left + (g.deltaX / s)) //d.setOffset(this, data.left + (g.deltaX / s))
r.transform({x: data.left + (g.deltaX / s)})
/* XXX this seems to offer no speed advantages /* XXX this seems to offer no speed advantages
* vs. .setOffset(..) but does not play * vs. .setOffset(..) but does not play
* well with .updateRibbon(..) * well with .updateRibbon(..)
$(this) r
.velocity('stop') .velocity('stop')
.velocity({ .velocity({
translateX: data.left + (g.deltaX / s), translateX: data.left + (g.deltaX / s),
@ -1896,19 +1916,44 @@ var ControlActions = actions.Actions({
// when done... // when done...
if(g.isFinal){ if(g.isFinal){
r.removeData('drag-data')
// XXX this seems to have trouble with off-screen images...
var central = that.ribbons.getImageByPosition('center', r) var central = that.ribbons.getImageByPosition('center', r)
// check if central if off screen, if yes,
// nudge it into user-accessible area...
//
// we are fully off screen -- focus first/last image...
if(central == null){
var gid = that.data.getImage(
r.offset().left < 0 ? -1 : 0, rgid)
that.centerImage(gid)
central = that.ribbons.getImage(gid)
// partly out the left -- show last image...
} else if(central.offset().left < 0){
r.transform({
x: r.transform('x') - (central.offset().left / s)
})
// partly out the right -- show first image...
} else if(central.offset().left + (central.width()*s)
> that.ribbons.viewer.width()){
r.transform({
x: r.transform('x')
+ (that.ribbons.viewer.width()
- (central.offset().left
+ central.width()*s)) / s
})
}
// load stuff if needed... // load stuff if needed...
that.updateRibbon(central) that.updateRibbon(central)
/*
// XXX add inertia.... // XXX add inertia....
/* XXX
console.log('!!!!', g.velocityX)
r.velocity({ r.velocity({
translateX: (data.left + g.deltaX + (g.velocityX * 10)) +'px' translateX: (data.left + ((g.deltaX + (g.velocityX * 10)) / s)) +'px'
}, 'easeInSine') }, 'easeInSine')
*/ */
@ -1916,21 +1961,27 @@ var ControlActions = actions.Actions({
if(that.config['focus-central-image'] == 'silent'){ if(that.config['focus-central-image'] == 'silent'){
var gid = that.ribbons.getElemGID(central) var gid = that.ribbons.getElemGID(central)
// XXX is this the right way to do this??? that.data.focusImage(gid, rgid)
that.data.focusImage(gid) that.ribbons.focusImage(a.current)
that.ribbons.focusImage(gid)
// focus central image in a normal manner... // focus central image in a normal manner...
} else if(that.config['focus-central-image']){ } else if(that.config['focus-central-image']){
that.focusImage(that.ribbons.getElemGID(central)) var gid = that.ribbons.getElemGID(central)
that.data.focusImage(gid, rgid)
that.focusImage()
} }
data = false
that.ribbonPanning.post(that, post_handlers)
setTimeout(function(){ setTimeout(function(){
that.__control_in_progress -= 1 that.__control_in_progress -= 1
if(that.__control_in_progress <= 0){ if(that.__control_in_progress <= 0){
delete that.__control_in_progress delete that.__control_in_progress
} }
}, 50) }, that.config['control-in-progress-timeout'] || 100)
} }
}) })
} }

View File

@ -358,6 +358,9 @@ function Action(name, doc, ldoc, func){
meth.func = func meth.func = func
// make introspection be a bit better...
meth.toString = func.toString.bind(func)
return meth return meth
} }
// this will make action instances behave like real functions... // this will make action instances behave like real functions...
@ -370,24 +373,60 @@ Action.prototype.chainApply = function(context, inner, args){
var res = context var res = context
var outer = this.name var outer = this.name
var data = this.pre(context, args)
// call the inner action/function if preset....
if(inner){
//res = inner instanceof Function ?
inner instanceof Function ?
inner.call(context, args)
: inner instanceof Array && inner.length > 0 ?
context[inner.pop()].chainCall(context, inner, args)
: typeof(inner) == typeof('str') ?
context[inner].chainCall(context, null, args)
: null
}
return this.post(context, data)
}
Action.prototype.chainCall = function(context, inner){
return this.chainApply(context, inner, args2array(arguments).slice(2))
}
// The pre/post stage runners...
//
// .pre(context, args)
// -> data
//
// .post(context, data)
// -> result
//
Action.prototype.pre = function(context, args){
args = args || []
var res = context
var outer = this.name
var getHandlers = context.getHandlers || MetaActions.getHandlers var getHandlers = context.getHandlers || MetaActions.getHandlers
var isToggler = context.isToggler || MetaActions.isToggler var isToggler = context.isToggler || MetaActions.isToggler
// get .__call__(..) wrapper handler list...
var call_wrapper = outer != '__call__' && inner != '__call__' ?
getHandlers.call(context, '__call__')
: []
// get the handler list... // get the handler list...
var handlers = getHandlers.call(context, outer) var handlers = getHandlers.call(context, outer)
// special case: toggler -- do not handle special args... // special case: toggler -- do not handle special args...
// XXX should this be here???
if(isToggler.call(context, outer) if(isToggler.call(context, outer)
&& args.length == 1 && args.length == 1
&& (args[0] == '?' || args[0] == '??')){ && (args[0] == '?' || args[0] == '??')){
return handlers.slice(-1)[0].pre.apply(context, args) return {
result: handlers.slice(-1)[0].pre.apply(context, args),
}
} }
var call_wrapper = outer != '__call__' ?
getHandlers.call(context, '__call__')
: []
// wrapper handlers: pre phase... // wrapper handlers: pre phase...
call_wrapper = call_wrapper call_wrapper = call_wrapper
.map(function(a){ .map(function(a){
@ -430,25 +469,29 @@ Action.prototype.chainApply = function(context, inner, args){
return a return a
}) })
// call the inner action/function if preset.... // return context if nothing specific is returned...
if(inner){
//res = inner instanceof Function ?
inner instanceof Function ?
inner.call(context, args)
: inner instanceof Array && inner.length > 0 ?
context[inner.pop()].chainCall(context, inner, args)
: typeof(inner) == typeof('str') ?
context[inner].chainCall(context, null, args)
: null
}
// return this if nothing specific is returned...
res = res === undefined ? context : res res = res === undefined ? context : res
return {
arguments: args,
wrapper: call_wrapper,
handlers: handlers,
result: res,
}
}
Action.prototype.post = function(context, data){
var res = data.result || context
var args = data.arguments || []
// the post handlers get the result as the first argument... // the post handlers get the result as the first argument...
args.splice(0, 0, res) args.splice(0, 0, res)
var outer = this.name
// handlers: post phase... // handlers: post phase...
handlers data.handlers && data.handlers
// NOTE: post handlers are called LIFO -- last defined last... // NOTE: post handlers are called LIFO -- last defined last...
.reverse() .reverse()
.forEach(function(a){ .forEach(function(a){
@ -459,7 +502,7 @@ Action.prototype.chainApply = function(context, inner, args){
}) })
// wrapper handlers: post phase... // wrapper handlers: post phase...
call_wrapper data.wrapper && data.wrapper
// NOTE: post handlers are called LIFO -- last defined last... // NOTE: post handlers are called LIFO -- last defined last...
.reverse() .reverse()
.forEach(function(a){ .forEach(function(a){
@ -469,13 +512,8 @@ Action.prototype.chainApply = function(context, inner, args){
: a.post.call(context, res, outer, args.slice(1))) : a.post.call(context, res, outer, args.slice(1)))
}) })
// action result...
return res return res
} }
Action.prototype.chainCall = function(context, inner){
return this.chainApply(context, inner, args2array(arguments).slice(2))
}
// A base action-set object... // A base action-set object...
// //

View File

@ -1027,7 +1027,7 @@ var RibbonsPrototype = {
// sort images by distance... // sort images by distance...
.sort(function(a, b){ return Math.abs(a[0]) - Math.abs(b[0]) }) .sort(function(a, b){ return Math.abs(a[0]) - Math.abs(b[0]) })
var a = res[0][0] var a = res[0] ? res[0][0] : null
var b = res[1] ? res[1][0] : null var b = res[1] ? res[1][0] : null
// we have two images that are about the same distance from // we have two images that are about the same distance from
@ -1041,7 +1041,8 @@ var RibbonsPrototype = {
// a single hit... // a single hit...
} else { } else {
return res[0][1] // NOTE: if no image is on screen this will get nothing...
return res[0] ? res[0][1] : null
} }
}, },