reworked ribbon traverse and alignment + minor fix...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2015-12-03 00:58:43 +03:00
parent c1c369d3ce
commit 4e31790f95
4 changed files with 257 additions and 16 deletions

View File

@ -297,10 +297,10 @@ var RibbonsPrototype = {
// XXX try and make image size the product of vmin and scale...
// XXX this might break when no images are loaded and proportions
// are not square...
getVisibleImageSize: function(dim, scale){
getVisibleImageSize: function(dim, scale, img){
scale = scale || this.getScale()
dim = dim == null ? 'width' : dim
var img = this.viewer.find(IMAGE)
img = img || this.viewer.find(IMAGE)
var tmp
// if no images are loaded create one temporarily....
@ -350,6 +350,117 @@ var RibbonsPrototype = {
return H/h
},
// Get an image at a relative to viewer position...
//
// Get central image in current ribbon:
// .getImageByPosition()
// -> image
//
// Get central image closest to current:
// .getImageByPosition('current'[, <ribbon>])
// -> image
//
// Get central image closest to html element:
// .getImageByPosition(<elem>[, <ribbon>])
// -> image
//
// Get image in a specific ribbon:
// .getImageByPosition('left'[, <ribbon>])
// .getImageByPosition('center'[, <ribbon>])
// .getImageByPosition('right'[, <ribbon>])
// -> image
//
// This can return a pair of images when position is either 'center',
// 'current' or a jquery object, this can happen when the two
// candidates are closer to the target than delta.
//
//
// NOTE: if no ribbon is given, current ribbon is assumed.
// NOTE: <ribbon> is the same as expected by .getRibbon(..)
// NOTE: position can also be an image...
// NOTE: delta is used ONLY if position is either 'center', 'current'
// or an jQuery object...
getImageByPosition: function(position, ribbon, delta){
position = position || 'center'
ribbon = this.getRibbon(ribbon)
var viewer = this.viewer
var W = viewer.outerWidth()
var L = viewer.offset().left
var target = position == 'current' ? this.getImage()
: position == 'center' ? viewer
: position == 'left' ? L
: position == 'right' ? L + W
: position
// unknown keyword...
if(target == null){
return $()
// center of an element...
} else if(typeof(target) != typeof(123)){
target = $(target)
var w = target.hasClass('image') ?
this.getVisibleImageSize('width', null, target) :
target.outerWidth()
// NOTE: we will need delta only in this branch, i.e. when
// position is either 'current', 'center' or a jQuery
// object...
delta = delta || w / 10
target = target.offset().left + w/2
}
var that = this
var res = ribbon.find(IMAGE)
.toArray()
.map(function(img){
img = $(img)
var l = img.offset().left
var w = that.getVisibleImageSize('width', null, img)
// skip images not fully shown in viewer...
if(L > l || l+w > L+W){
return
}
// distance between centers...
if(position == 'center' || position == 'current'){
return [target - (l + w/2), img]
// distance between left edges...
} else if(position == 'left'){
return [target - l, img]
// distance between right edges...
} else {
return [target - (l + w), img]
}
})
// drop images outside the viewer...
.filter(function(e){ return e != null })
// sort images by distance...
.sort(function(a, b){ return Math.abs(a[0]) - Math.abs(b[0]) })
var a = res[0][0]
var b = res[1] ? res[1][0] : null
// we have two images that are about the same distance from
// target...
// NOTE: this is a one-dimentional filter so the can not be more
// than two hits...
// NOTE: delta is used ONLY if position is either 'center',
// 'current' or an jQuery object...
if(b && (a >= 0) != (b >= 0) && Math.abs(a + b) < delta){
return $([res[0][1][0], res[1][1][0]])
// a single hit...
} else {
return res[0][1]
}
},
// Get ribbon set scale...
//
getScale: function(){

View File

@ -126,7 +126,7 @@ if(typeof(glob) != 'undefined'){
window.loadMBFWR1 = function(logger){
a.loadPath('L:/mnt/hdd15 (photo)/NTFS2/media/img/my/work/20151022 - MBFWR (1),/preview (RAW)/', logger)
a.loadIndex('L:/mnt/hdd15 (photo)/NTFS2/media/img/my/work/20151022 - MBFWR (1),/preview (RAW)/', logger)
}

View File

@ -79,13 +79,6 @@ module.GLOBAL_KEYBOARD = {
F4: {
alt: 'close',
/*
alt: doc('Close viewer',
function(){
window.close()
return false
}),
*/
},
Q: {
meta: 'close',

View File

@ -165,6 +165,16 @@ actions.Actions({
config: {
// see .direction for details...
'steps-to-change-direction': 3,
// determines the image selection mode when focusing ribbons...
//
// supported modes:
// 'order' - select image closest to current in order
// 'first' - select first image
// 'last' - select last image
// 'visual' - select image closest visually
//'ribbon-focus-mode': 'order',
'ribbon-focus-mode': 'visual',
},
// basic state...
@ -283,8 +293,16 @@ actions.Actions({
function(img, list){
this.data.focusImage(img, list)
}],
// Focuses a ribbon by selecting an image in it...
//
// modes supported:
// 'order' - focus closest image to current in order
// 'first'/'last' - focus first/last image in ribbon
// 'visual' - focus visually closest to current image
//
// NOTE: default mode is set in .config.ribbon-focus-mode
focusRibbon: ['Navigate/Focus Ribbon',
function(target){
function(target, mode){
var data = this.data
var r = data.getRibbon(target)
if(r == null){
@ -293,15 +311,36 @@ actions.Actions({
var c = data.getRibbonOrder()
var i = data.getRibbonOrder(r)
mode = mode || this.config['ribbon-focus-mode'] || 'order'
// NOTE: we are not changing the direction here based on
// this.direction as swap will confuse the user...
var direction = c < i ? 'before' : 'after'
var t = data.getImage(r, direction)
// closest image in order...
if(mode == 'order'){
var t = data.getImage(r, direction)
// if there are no images in the requied direction, try the
// other way...
t = t == null ? data.getImage(r, direction == 'before' ? 'after' : 'before') : t
// if there are no images in the requied direction, try the
// other way...
t = t == null ? data.getImage(r, direction == 'before' ? 'after' : 'before') : t
// first/last image...
} else if(mode == 'first' || mode == 'last'){
var t = data.getImage(mode, r)
// visually closest image...
//} else if(mode == 'visual'){
} else {
var ribbons = this.ribbons
var t = ribbons.getImageByPosition('current', r)
if(t.length > 1){
t = t.eq(direction == 'before' ? 0 : 1)
}
t = ribbons.getElemGID(t)
}
this.focusImage(t, r)
}],
@ -1984,6 +2023,66 @@ module.SingleImageView = ImageGridFeatures.Feature({
//---------------------------------------------------------------------
// These feature glue traverse and ribbon alignment...
// XXX manual align needs more work...
var AutoAlignRibbons =
module.AutoAlignRibbons = ImageGridFeatures.Feature({
title: '',
doc: '',
tag: 'ui-ribbon-auto-align',
depends: ['ui'],
exclusive: ['ui-ribbon-align'],
config: {
// Control image selection and optionally ribbon alignment...
//
// NOTE: this only supports the following modes:
// - 'visual'
// - 'order'
// - 'fisrt'
// - 'manual'
// NOTE: if 'ribbon-align-mode' is not null this can be set to
// any mode without restriction.
//'ribbon-focus-mode': 'order',
'ribbon-focus-mode': 'visual',
// control ribbon alignment...
//
// NOTE: when this is null then 'ribbon-focus-mode' will be used...
// NOTE: this supports the same modes as 'ribbon-focus-mode'...
'ribbon-align-mode': null,
},
handlers: [
['focusImage.post',
function(){
var mode = this.config['ribbon-align-mode']
|| this.config['ribbon-focus-mode']
if(mode == 'visual' || mode == 'order'){
this.alignByOrder()
} else if(mode == 'first'){
this.alignByFirst()
// manual...
// XXX is this correct???
} else {
this
.centerRibbon()
.centerImage()
}
}],
],
})
// XXX add a feature not to align the ribbons and focus the central
// image on next prev ribbon...
// XXX in general need a way to control .nextRibbon(..)/.prevRibbon(..)
// image selection...
// XXX this should also define up/down navigation behavior e.g. what to
// focus on next/prev ribbon...
@ -1998,6 +2097,11 @@ module.AlignRibbonsToImageOrder = ImageGridFeatures.Feature({
depends: ['ui'],
exclusive: ['ui-ribbon-align'],
config: {
//'ribbon-focus-mode': 'order',
'ribbon-focus-mode': 'visual',
},
handlers: [
['focusImage.post', function(){ this.alignByOrder() }]
],
@ -2013,11 +2117,41 @@ module.AlignRibbonsToFirstImage = ImageGridFeatures.Feature({
depends: ['ui'],
exclusive: ['ui-ribbon-align'],
config: {
'ribbon-focus-mode': 'first',
},
handlers: [
['focusImage.post', function(){ this.alignByFirst() }],
],
})
// XXX needs more work...
// XXX need to save position in some way, ad on each load the same
// initial state will get loaded...
// ...also would need an initial state...
var ManualAlignRibbons =
module.ManualAlignRibbons = ImageGridFeatures.Feature({
title: '',
doc: '',
tag: 'ui-ribbon-manual-align',
depends: ['ui'],
exclusive: ['ui-ribbon-align'],
config: {
'ribbon-focus-mode': 'visual',
},
handlers: [
['focusImage.post', function(){
this
.centerRibbon()
.centerImage()
}],
],
})
//---------------------------------------------------------------------
@ -3477,7 +3611,10 @@ ImageGridFeatures.Feature('viewer-testing', [
'ui',
// features...
'ui-ribbon-align-to-order',
'ui-ribbon-auto-align',
//'ui-ribbon-align-to-order',
//'ui-ribbon-align-to-first',
//'ui-ribbon-manual-align',
'ui-single-image-view',
'ui-partial-ribbons',