From 831e82a28a82f857c939306e5aca9883b97779c6 Mon Sep 17 00:00:00 2001 From: "Alex A. Naanou" Date: Sat, 29 Jul 2017 21:39:47 +0300 Subject: [PATCH] experimenting... Signed-off-by: Alex A. Naanou --- ui (gen4)/experiments/preact-ribbons.html | 84 +++++-- ui (gen4)/features/ui-blank-render.js | 68 ++++++ ui (gen4)/features/ui-preact-render.js | 261 +++++++++++++++++++--- ui (gen4)/features/ui-ribbons.js | 4 +- ui (gen4)/features/ui.js | 3 + ui (gen4)/imagegrid/ribbons.js | 126 ++++++----- 6 files changed, 434 insertions(+), 112 deletions(-) diff --git a/ui (gen4)/experiments/preact-ribbons.html b/ui (gen4)/experiments/preact-ribbons.html index 2fe294c1..901067f9 100755 --- a/ui (gen4)/experiments/preact-ribbons.html +++ b/ui (gen4)/experiments/preact-ribbons.html @@ -19,6 +19,7 @@ border-bottom: solid 5px red; } +.mark, .image { position: relative; display: inline-block; @@ -28,14 +29,37 @@ outline: solid 1px blue; background: silver; + + vertical-align: middle; +} +.image:after { + content: attr(gid); } .current.image { background: gray; } .mark { - position: absolute; + margin-left: -100px; + background: none; + + pointer-events: none; } +.mark:after { + position: absolute; + content: ""; + top: 0; + right: 0; + + width: 0; + height: 0; + border: solid 10px red; + border-bottom-color: transparent; + border-left-color: transparent; + + pointer-events: auto; +} + @@ -63,7 +87,7 @@ var stub_data = { order: [].slice.call('abcdefghijklmopqrstuvwxyz'), tags: { - a: [].slice.call('ahdtu'), + selected: [].slice.call('ahdtu'), b: [].slice.call('adxz'), }, @@ -109,11 +133,23 @@ class IGRibbon extends preact.Component { var data = props.data var ribbon = props.gid - var images = data.ribbons[ribbon].map(function(gid){ - return h(IGImage, { - gid: gid, - data: data - })}) + var images = data.ribbons[ribbon] + .map(function(gid){ + var marks = data.tags.selected.indexOf(gid) >= 0 ? + h(IGImageMark, { + gid: gid, + type: 'selected', + data: data, + }) + : [] + return [ + h(IGImage, { + gid: gid, + data: data, + })].concat(marks) + }) + .reduce(function(a, b){ return a.concat(b) }) + .filter(function(a){ return !!a }) var base = data.base == ribbon ? ['base'] : [] @@ -146,14 +182,22 @@ class IGImage extends preact.Component { // XXX background-image... }, - // XXX experiemnt... + // XXX STUB onClick: function(evt){ + // toggle tag... + if(data.current == gid){ + var selected = data.tags.selected = data.tags.selected || [] + selected.indexOf(gid) < 0 ? + selected.push(gid) + : selected.splice(selected.indexOf(gid), 1) + } + + // set current... data.current = gid + render() - } - }, [ - gid - ]) + }, + }) } } @@ -161,10 +205,22 @@ class IGImage extends preact.Component { // - image mark class IGImageMark extends preact.Component { render(props, state){ + var gid = props.gid + var type = props.type + var data = props.data + return h('div', { - classList: ['mark'], - gid: props.gid, + classList: ['mark'].concat([type]).join(' '), + gid: gid, + + // XXX STUB... + // ...and there is no way to add the mark back... + onClick: function(evt){ + data.tags[type].splice(data.tags[type].indexOf(gid), 1) + + render() + }, }) } } diff --git a/ui (gen4)/features/ui-blank-render.js b/ui (gen4)/features/ui-blank-render.js index ed58f451..c086a716 100755 --- a/ui (gen4)/features/ui-blank-render.js +++ b/ui (gen4)/features/ui-blank-render.js @@ -26,13 +26,26 @@ var ribbons = require('imagegrid/ribbons') /*********************************************************************/ var RibbonsClassPrototype = { + // This is needed to calculate image size when no images are loaded... + createImage: function(){ + // XXX + }, + // XXX } RibbonsClassPrototype.__proto__ = ribbons.BaseRibbons.prototype.__proto__ var RibbonsPrototype = { + viewer: null, + + createImage: RibbonsClassPrototype.createImage, + // XXX + + __init__: function(viewer, images){ + // XXX + }, } RibbonsPrototype.__proto__ = ribbons.BaseRibbons.prototype @@ -77,14 +90,36 @@ var RenderActions = actions.Actions({ }], reload: [ function(){ + // full reload... + if(force == 'full'){ + //this.stop() + /* + killAllWorkers() + .done(function(){ + reload() + }) + */ + return location.reload() + } + + if(!this.ribbons){ + return + } + // XXX }], refresh: [ function(){ + if(!this.ribbons){ + return + } // XXX }], clear: [ function(){ + if(!this.ribbons){ + return + } // XXX }], @@ -106,6 +141,9 @@ var RenderActions = actions.Actions({ viewScale: ['- Zoom/', function(scale){ + if(!this.ribbons){ + return + } if(scale == null || scale == '?'){ return // XXX get scale... } @@ -116,22 +154,43 @@ var RenderActions = actions.Actions({ }], fitImage: ['Zoom/Fit image', function(count, overflow){ + if(!this.ribbons){ + return + } if(count == '?'){ return // XXX get size... } this.resizing.chainCall(this, function(){ + if(count != null){ + overflow = overflow == false ? 0 : overflow + var o = overflow != null ? overflow + : count % 2 != 1 ? 0 + : (this.config['fit-overflow'] || 0) + count += o + } + + // set the scale... + // XXX + + // refresh image previews... // XXX }, 'screenwidth', count, overflow) }], fitRibbon: ['Zoom/Fit ribbon vertically', function(count, whole){ + if(!this.ribbons){ + return + } if(count == '?'){ return // XXX get size... } this.resizing.chainCall(this, function(){ // XXX set size... + + // XXX refresh image previews... + }, 'screenheight', count, whole) }], @@ -139,15 +198,24 @@ var RenderActions = actions.Actions({ centerImage: ['- Interface/Center an image in ribbon horizontally', function(target, align, offset, scale){ + if(!this.ribbons){ + return + } // XXX }], centerRibbon: ['- Interface/Center a ribbon vertically', function(target){ + if(!this.ribbons){ + return + } // XXX }], ribbonRotation: ['- Interface|Ribbon/', function(angle){ + if(!this.ribbons){ + return + } // XXX }], }) diff --git a/ui (gen4)/features/ui-preact-render.js b/ui (gen4)/features/ui-preact-render.js index 735b363f..9c41417c 100755 --- a/ui (gen4)/features/ui-preact-render.js +++ b/ui (gen4)/features/ui-preact-render.js @@ -37,33 +37,28 @@ var ribbons = require('imagegrid/ribbons') // - do we update preview in Preact render or outside? // -// render: -// - ribbon-set -// - ribbon-locator -// - current-indicator (???) -// -// * this is static and only created once... + class IGRibbonSet extends preact.Component { render(props, state){ - - // XXX need: - // - scale - // - ribbons - - var ribbons = data.ribbon_order - .map(function(gid){ return h(IGRibbon, { - ribbon: gid, - // XXX + var data = props.data + var ribbons = data.ribbon_order.map(function(gid){ + return h(IGRibbon, { + gid: gid, + current: data.current, + base: data.base, + data: data }) }) + var s = props.scale || 1 - return h('div.ribbon-set', + return h('div', { + className: 'ribbon-set', style: { transform: 'scale('+ s +', '+ s +')', }, }, [ - h('div.current-marker'), - h('div.ribbon-locator', null, ribbons), + h('div', {className: 'current-marker'}), + h('div', {className: 'ribbon-locator'}, ribbons), ]) } } @@ -72,8 +67,42 @@ class IGRibbonSet extends preact.Component { // - ribbon // - images // - image marks +// +// XXX needs horizontal align... class IGRibbon extends preact.Component { render(props, state){ + var data = props.data + var ribbon = props.gid + + var images = data.ribbons[ribbon] + .map(function(gid){ + var marks = data.tags.selected.indexOf(gid) >= 0 ? + h(IGImageMark, { + gid: gid, + type: 'selected', + data: data, + }) + : [] + return [ + h(IGImage, { + gid: gid, + data: data, + })].concat(marks) + }) + .reduce(function(a, b){ return a.concat(b) }) + .filter(function(a){ return !!a }) + + var base = data.base == ribbon ? ['base'] : [] + + return h('div', + { + classList: ['ribbon'].concat(base).join(' '), + + gid: props.gid, + style: { + // XXX offset... + }, + }, images) } } @@ -81,6 +110,21 @@ class IGRibbon extends preact.Component { // - image class IGImage extends preact.Component { render(props, state){ + var data = props.data || {} + var gid = props.gid + + return h('div', + { + classList: ['image'] + .concat(data.current == gid ? ['current'] : []) + .join(' '), + gid: gid || '', + style: { + // XXX background-image... + }, + + // XXX handle clicks??? + }) } } @@ -88,6 +132,15 @@ class IGImage extends preact.Component { // - image mark class IGImageMark extends preact.Component { render(props, state){ + var gid = props.gid + var type = props.type + var data = props.data + + return h('div', + { + classList: ['mark'].concat([type]).join(' '), + gid: gid, + }) } } @@ -96,13 +149,45 @@ class IGImageMark extends preact.Component { //--------------------------------------------------------------------- var RibbonsClassPrototype = { - // XXX + // XXX this is almost exclusively needed for determining scale... + createImage: function(){ + return preact.render(h(IGImage)) }, } RibbonsClassPrototype.__proto__ = ribbons.BaseRibbons.prototype.__proto__ var RibbonsPrototype = { - // XXX + viewer: null, + dom: null, + + createImage: RibbonsClassPrototype.createImage, + + update: function(data, full){ + if(!data){ + return + } + + full + && this.clear() + + this.dom = preact.render( + h(IGRibbonSet, { + data: data, + images: this.images || {}, + scale: this.scale() || 1, + }), + this.viewer[0], + this.dom) + + return this + }, + clear: function(){ + if(this.dom){ + this.dom.remove() + delete this.dom + } + return this + }, } RibbonsPrototype.__proto__ = ribbons.BaseRibbons.prototype @@ -116,6 +201,22 @@ object.makeConstructor('Ribbons', /*********************************************************************/ +// Checklist: +// - full ribbons: +// - build the initial DOM - DONE +// - centering - DONE +// - scaling - DONE (save/restore does not work) +// - ribbon up/down navigation - XXX +// XXX BUG: up does not hit limit on top ribbon, +// similar thing sometimes happened on down... +// XXX see if we need to put .focusRibbon(..) in ui??? +// - shifting images - XXX +// - preview setting - +// - marks - +// - partial ribbons: +// - XXX +// +// var RenderActions = actions.Actions({ get dom(){ @@ -143,18 +244,47 @@ var RenderActions = actions.Actions({ this.reload() } }], + // XXX do a full reload... reload: [ - function(){ + function(force){ + // full reload... + if(force == 'full'){ + //this.stop() + /* + killAllWorkers() + .done(function(){ + reload() + }) + */ + return location.reload() + } + + // XXX is this correct here??? + this.ribbons.preventTransitions() + + if(!this.ribbons){ + return + } + // XXX need to get the data... // XXX + + this.ribbons.update(this.data, force) + + this.ribbons.restoreTransitions() }], + // XXX refresh the previews... refresh: [ function(){ + if(!this.ribbons){ + return + } + // XXX need to get the data... // XXX + + this.ribbons.update(this.data) }], clear: [ - function(){ - // XXX - }], + function(){ this.ribbons && this.ribbons.clear() }], resizing: [ core.notUserCallable(function(unit, size, overflow){ @@ -174,32 +304,56 @@ var RenderActions = actions.Actions({ viewScale: ['- Zoom/', function(scale){ + if(!this.ribbons){ + return + } if(scale == null || scale == '?'){ - return // XXX get scale... + return this.ribbons.scale() } this.resizing.chainCall(this, function(){ - // XXX set scale... + this.ribbons.scale(scale) }, 'scale', scale) }], fitImage: ['Zoom/Fit image', function(count, overflow){ + if(!this.ribbons){ + return + } if(count == '?'){ - return // XXX get size... + return this.ribbons.getScreenWidthImages() } this.resizing.chainCall(this, function(){ - // XXX + if(count != null){ + overflow = overflow == false ? 0 : overflow + var o = overflow != null ? overflow + : count % 2 != 1 ? 0 + : (this.config['fit-overflow'] || 0) + count += o + } + + // set the scale... + this.ribbons.fitImage(count) + + // XXX refresh image previews... + }, 'screenwidth', count, overflow) }], fitRibbon: ['Zoom/Fit ribbon vertically', function(count, whole){ + if(!this.ribbons){ + return + } if(count == '?'){ - return // XXX get size... + return this.ribbons.getScreenHeightRibbons() } this.resizing.chainCall(this, function(){ - // XXX set size... + this.ribbons.fitRibbon(count, whole) + + // XXX refresh image previews... + }, 'screenheight', count, whole) }], @@ -207,17 +361,45 @@ var RenderActions = actions.Actions({ centerImage: ['- Interface/Center an image in ribbon horizontally', function(target, align, offset, scale){ - // XXX - }], + this.ribbons && this.ribbons.centerImage(target, align, offset, scale) }], centerRibbon: ['- Interface/Center a ribbon vertically', function(target){ - // XXX - }], + this.ribbons && this.ribbons.centerRibbon(target) }], ribbonRotation: ['- Interface|Ribbon/', function(angle){ // XXX }], + + + // XXX should these be here, in ui or in ribbons??? + // XXX these are identical to features/ui-ribbons.js + focusRibbon: [ + function(target, mode){ + mode = mode || this.config['ribbon-focus-mode'] + + var c = this.data.getRibbonOrder() + var i = this.data.getRibbonOrder(target) + // NOTE: we are not changing the direction here based on + // this.direction as swap will confuse the user... + var direction = c < i ? 'before' : 'after' + + if(mode == 'visual'){ + var ribbons = this.ribbons + var r = this.data.getRibbon(target) + var t = ribbons.getImageByPosition('current', r) + + if(t.length > 1){ + t = t.eq(direction == 'before' ? 0 : 1) + } + + t = ribbons.elemGID(t) + + this.focusImage(t, r) + } + }], + + }) var Render = @@ -234,7 +416,16 @@ module.Render = core.ImageGridFeatures.Feature({ actions: RenderActions, handlers: [ - // XXX + [[ + 'shiftImageTo', + 'shiftImageUp', + 'shiftImageDown', + 'shiftImageLeft', + 'shiftImageRight', + ], function(){ + // XXX stub... + this.reload() + }], ], }) diff --git a/ui (gen4)/features/ui-ribbons.js b/ui (gen4)/features/ui-ribbons.js index 376b744e..6309406a 100755 --- a/ui (gen4)/features/ui-ribbons.js +++ b/ui (gen4)/features/ui-ribbons.js @@ -153,7 +153,7 @@ actions.Actions({ reload() }) */ - location.reload() + return location.reload() } this.ribbons.preventTransitions() @@ -295,6 +295,8 @@ actions.Actions({ }], + // XXX should these be here, in ui or in ribbons??? + // XXX these are identical to features/ui-preact-render.js focusImage: [ function(target, list){ return function(){ diff --git a/ui (gen4)/features/ui.js b/ui (gen4)/features/ui.js index 9be37c45..fd6e4b5f 100755 --- a/ui (gen4)/features/ui.js +++ b/ui (gen4)/features/ui.js @@ -1314,6 +1314,7 @@ var ControlActions = actions.Actions({ // XXX do not do anything on viewer focus... (???) // XXX depends on .ribbons... + // XXX uses: .focusImage(..) toggleImageClickHandling: ['Interface/Image click handling', toggler.Toggler(null, function(_, new_state){ @@ -1518,6 +1519,7 @@ var ControlActions = actions.Actions({ // ...found the problem, need to disable transitions for this // to work semi smoothly... // XXX depends on .ribbons... + // XXX uses: .focusImage(..) toggleRibbonPanHandling: ['Interface/Ribbon pan handling', toggler.Toggler(null, function(_, new_state){ @@ -1756,6 +1758,7 @@ var ControlActions = actions.Actions({ // XXX BUG?: acceleration seems to be increasing with time... // XXX add a "ribbonWheeling" ( ;) ) event a-la ribbonPanning... // XXX depends on .ribbons... + // XXX uses: .focusImage(..) toggleMouseWheelHandling: ['Interface/Mouse wheel handling', toggler.Toggler(null, function(_, new_state){ diff --git a/ui (gen4)/imagegrid/ribbons.js b/ui (gen4)/imagegrid/ribbons.js index 5960cbad..6ef1eb9c 100755 --- a/ui (gen4)/imagegrid/ribbons.js +++ b/ui (gen4)/imagegrid/ribbons.js @@ -350,7 +350,6 @@ var BaseRibbonsPrototype = { return this }, - // Get visible image tile size... // // .getVisibleImageSize() @@ -369,6 +368,7 @@ var BaseRibbonsPrototype = { // // XXX this might break when no images are loaded and proportions // are not square... + // XXX this depends on .createImage(..) getVisibleImageSize: function(dim, scale, img, force){ dim = dim == null ? 'width' : dim img = img || this.viewer.find(IMAGE) @@ -385,7 +385,7 @@ var BaseRibbonsPrototype = { // if no images are loaded create one temporarily.... if(img.length == 0){ - img = tmp = this.createImage('__tmp_image__') + img = tmp = $(this.createImage('__tmp_image__')) .css({ position: 'absolute', visibility: 'hidden', @@ -449,6 +449,68 @@ var BaseRibbonsPrototype = { return H/h }, + // Fit image to view... + // + // If n is given this will fit n images (default: 1) + // + // NOTE: this will never scale the view in a way that an image + // overflows either in height nor width. + // + // XXX might be useful to set origin before scaling... + fitImage: function(n, min){ + n = n || 1 + + // NOTE: this is width oriented... + var scale = this.getScreenWidthImages(1, min) / n + + // check bounds... + var H = this.viewer.height() + var h = this.getVisibleImageSize('height', 1) + + // n images will be higher than the viewer, adjust for height... + if(h*scale >= H){ + scale = H/h + } + + this + .scale(scale) + //.centerRibbon(null, null, scale) + //.centerImage(null, null, null, scale) + + return this + }, + // NOTE: if fit_whole_images is true (default) this will fit a discrete + // number of images in width... + // XXX this does not account for ribbon spacing... + fitRibbon: function(n, fit_whole_images){ + n = n || 1 + fit_whole_images = fit_whole_images == null ? true : false + + var scale = this.getScreenHeightRibbons(1) / n + + var w = this.getVisibleImageSize('width', 1) + var W = this.viewer.width() + + // n ribbons will be wider than the viewer... + if(w*scale >= W){ + scale = W/w + } + + // shift the scale to the point where screen width is a whole + // number of images... + if(fit_whole_images){ + var d = this.getScreenWidthImages(scale) + d = d / Math.ceil(d) + + scale *= d + } + + this.scale(scale) + + return this + }, + + // Contextual getters... // Get ribbon-set... @@ -2489,66 +2551,6 @@ var RibbonsPrototype = { return this.flipImage(target, 'horizontal', reference) }, - // Fit image to view... - // - // If n is given this will fit n images (default: 1) - // - // NOTE: this will never scale the view in a way that an image - // overflows either in height nor width. - // - // XXX might be useful to set origin before scaling... - fitImage: function(n, min){ - n = n || 1 - - // NOTE: this is width oriented... - var scale = this.getScreenWidthImages(1, min) / n - - // check bounds... - var H = this.viewer.height() - var h = this.getVisibleImageSize('height', 1) - - // n images will be higher than the viewer, adjust for height... - if(h*scale >= H){ - scale = H/h - } - - this - .scale(scale) - //.centerRibbon(null, null, scale) - //.centerImage(null, null, null, scale) - - return this - }, - // NOTE: if fit_whole_images is true (default) this will fit a discrete - // number of images in width... - // XXX this does not account for ribbon spacing... - fitRibbon: function(n, fit_whole_images){ - n = n || 1 - fit_whole_images = fit_whole_images == null ? true : false - - var scale = this.getScreenHeightRibbons(1) / n - - var w = this.getVisibleImageSize('width', 1) - var W = this.viewer.width() - - // n ribbons will be wider than the viewer... - if(w*scale >= W){ - scale = W/w - } - - // shift the scale to the point where screen width is a whole - // number of images... - if(fit_whole_images){ - var d = this.getScreenWidthImages(scale) - d = d / Math.ceil(d) - - scale *= d - } - - this.scale(scale) - - return this - }, } RibbonsPrototype.__proto__ = BaseRibbonsPrototype