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...
['saveWorkspace',
core.makeWorkspaceConfigWriter(

View File

@ -1800,8 +1800,25 @@ var ControlActions = actions.Actions({
'focus-central-image': 'silent',
'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...
toggleRibbonPanHandling: ['Interface/Toggle ribbon pan handling',
@ -1817,6 +1834,9 @@ var ControlActions = actions.Actions({
// XXX
var that = this
var r = this.ribbons.getRibbon(target)
var rgid = this.ribbons.getElemGID(r)
var data = false
var post_handlers
// setup dragging...
if(r.length > 0 && !r.hasClass('draggable')){
@ -1835,17 +1855,16 @@ var ControlActions = actions.Actions({
//evt.stopPropagation()
// XXX stop all previous animations...
//r.velocity("stop")
r.velocity("stop")
var d = that.ribbons.dom
var s = that.scale
var g = evt.gesture
var data = r.data('drag-data')
var s = that.scale
// we just started...
if(!data){
that.__control_in_progress = (that.__control_in_progress || 0) + 1
post_handlers = that.ribbonPanning.pre(that, [rgid])
// hide and remove current image indicator...
// NOTE: it will be reconstructed on
@ -1860,20 +1879,21 @@ var ControlActions = actions.Actions({
})
// store initial position...
var data = {
left: d.getOffset(this).left,
data = {
//left: d.getOffset(this).left,
left: $(this).transform('x'),
pointers: g.pointers.length,
}
r.data('drag-data', data)
}
// 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
* vs. .setOffset(..) but does not play
* well with .updateRibbon(..)
$(this)
r
.velocity('stop')
.velocity({
translateX: data.left + (g.deltaX / s),
@ -1896,19 +1916,44 @@ var ControlActions = actions.Actions({
// when done...
if(g.isFinal){
r.removeData('drag-data')
// XXX this seems to have trouble with off-screen images...
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...
that.updateRibbon(central)
/*
// XXX add inertia....
/* XXX
console.log('!!!!', g.velocityX)
r.velocity({
translateX: (data.left + g.deltaX + (g.velocityX * 10)) +'px'
translateX: (data.left + ((g.deltaX + (g.velocityX * 10)) / s)) +'px'
}, 'easeInSine')
*/
@ -1916,21 +1961,27 @@ var ControlActions = actions.Actions({
if(that.config['focus-central-image'] == 'silent'){
var gid = that.ribbons.getElemGID(central)
// XXX is this the right way to do this???
that.data.focusImage(gid)
that.ribbons.focusImage(gid)
that.data.focusImage(gid, rgid)
that.ribbons.focusImage(a.current)
// focus central image in a normal manner...
} 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(){
that.__control_in_progress -= 1
if(that.__control_in_progress <= 0){
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
// make introspection be a bit better...
meth.toString = func.toString.bind(func)
return meth
}
// this will make action instances behave like real functions...
@ -370,24 +373,60 @@ Action.prototype.chainApply = function(context, inner, args){
var res = context
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 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...
var handlers = getHandlers.call(context, outer)
// special case: toggler -- do not handle special args...
// XXX should this be here???
if(isToggler.call(context, outer)
&& args.length == 1
&& (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...
call_wrapper = call_wrapper
.map(function(a){
@ -430,25 +469,29 @@ Action.prototype.chainApply = function(context, inner, args){
return a
})
// 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 if nothing specific is returned...
// return context if nothing specific is returned...
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...
args.splice(0, 0, res)
var outer = this.name
// handlers: post phase...
handlers
data.handlers && data.handlers
// NOTE: post handlers are called LIFO -- last defined last...
.reverse()
.forEach(function(a){
@ -459,7 +502,7 @@ Action.prototype.chainApply = function(context, inner, args){
})
// wrapper handlers: post phase...
call_wrapper
data.wrapper && data.wrapper
// NOTE: post handlers are called LIFO -- last defined last...
.reverse()
.forEach(function(a){
@ -469,13 +512,8 @@ Action.prototype.chainApply = function(context, inner, args){
: a.post.call(context, res, outer, args.slice(1)))
})
// action result...
return res
}
Action.prototype.chainCall = function(context, inner){
return this.chainApply(context, inner, args2array(arguments).slice(2))
}
// A base action-set object...
//

View File

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