added gen 3 ui code (still a work in progress...)

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2013-04-26 05:30:56 +04:00
parent 226140de06
commit 00151937ff
3 changed files with 483 additions and 0 deletions

61
ui/Gen3-TODO.otl Executable file
View File

@ -0,0 +1,61 @@
[_] 0% Generation 3 current todo
[_] manual sort -- shift left/right
[_] migrate the infinite ribbon code
[_] migrate the PortableMag generic code
[_] write basic align code
Generation 3 UI implementation
Infinite ribbon (lib)
cyclic ribbon
image block generation
image block update
ribbon head/tail management
| must be adaptive to current user scroll speed...
|
| at least a couple of screens at current zoom level...
Partial save/load
| save only a block or changed data...
Adaptive preview size (lib)
Multible ribbon (reuse)
User actions
| see [[controls.otl]] for basic actions...
|
| additional actions:
toggle mark image
| should include a set of marking operations
mark between
| mark all images between closest marks
unmark set
mark to/from
show marked only in ribbon (crop selection)
crop image
| shows a red/blue rectangle around image
|
| can be:
| turned +/- 90 deg
| turned arbitrarily
| scaled with constrained proportions
show crop as red rectangle
show only cropped area
show crop as black veil
add note to image
| a-la flickr notes...
edit IPCT
rotate image
| +/- 90 deg
UI modes
single ribbon
show images above/below in current ribbon
show marked only
multiple ribbons
show images above/below
show marked only
single image
TODO
action visual indication
.
| vim:set spell :

153
ui/ImageGrid.js Executable file
View File

@ -0,0 +1,153 @@
/**********************************************************************
*
*
*
*
* This should work over three contexts:
* - archive (full)
* full data available remotely
* handle global operations
* - local data (full or partial)
* full or partial set of data available locally
* handle global operations (if full data-set is available)
* handle local operations (if enough data is available)
* - local view (partial)
* only the rendered UI and cache
*
*
**********************************************************************/
var Context = {
// the selection query used to get data...
// NOTE: this should support operations to get next and prev batches if it's partial
// XXX we do not care about this yet
query: null,
// this can be:
// 'full' - indicating that all the data is available locally
// 'partial' - indicating that only part of the data is available
data_state: 'full',
data: {
// current image...
current: null,
// images, hashed by GUID...
images: {
},
// list of ribbons...
ribbons: [
// list of GUIDs in sort order...
[]
],
// list of marked GUIDs...
marked: [
],
}
view: null,
}
/**********************************************************************
* Helpers...
*/
// retrun viewer width in images...
function getViewImages(){
// XXX
}
/**********************************************************************
* User actions...
*/
/* Focus an image...
*
* n can be:
* - position relative to current
* -1 is previous image, +1 next
* - GUID
* if GUID is present in context select it.
*/
function focusImage(n){
// XXX
}
// shorthands...
function nextImage(){
return focusImage(1)
}
function prevImage(){
return focusImage(-1)
}
// NOTE: here n is the multiplier to the screen width of images...
function nextViewImages(n){
n = n == null ? 1 : n
return focusImage(getViewImages()*n)
}
function prevViewImages(n){
n = n == null ? -1 : -n
return focusImage(getViewImages()*n)
}
function firstImage(){
// XXX
}
function lastImage(){
// XXX
}
/* Focus a ribbon...
*
* n can be:
* - position relative to current
* -1 is previous image, +1 next
* - GUID (???)
* if GUID is present in context select it.
*
* NOTE: this will also focus the closest image...
*/
function focusRibbon(n){
// XXX
}
// shorthands...
function ribbonAbove(n){
n = n == null ? -1 : n
return focusRibbon(n)
}
function ribbonBelow(n){
n = n == null ? 1 : -n
return focusRibbon(n)
}
function topRibbon(){
// XXX
}
function bottomRibbon(){
// XXX
}
/* Marking...
*
* NOTE: n can be null, then current image is marked.
*/
function toggleMark(n){
// XXX
}
/**********************************************************************
* vim:set sw=4 ts=4 : */

269
ui/index.html Executable file
View File

@ -0,0 +1,269 @@
<html>
<head>
<title>ImageGrid.Viewer</title>
<style>
.viewer {
position: relative;
width: 800px;
height: 600px;
/*overflow: hidden;*/
overflow: auto;
border: solid blue 1px;
}
.ribbon-set {
}
.ribbon-set:empty:after {
position: absolute;
display: block;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
content: "Empty";
text-align: center;
}
.ribbon {
position: relative;
display: block;
height: auto;
min-width: 0px;
overflow: visible;
white-space: nowrap;
font-size: 0;
/*
margin-top: 20px;
margin-bottom: 20px;
*/
}
.ribbon:first-child {
margin-top: 0px;
}
.ribbon:last-child {
margin-bottom: 0px;
}
/* XXX do we actually need this? */
.current.ribbon {
}
.image {
position: relative;
display: inline-block;
vertical-align: middle;
text-align;left;
width: 100px;
height: 100px;
font-size: 12pt;
background: black;
box-sizing:border-box;
border: solid gray 1px;
color: white;
}
.current.image {
background: red;
}
</style>
<script src="jquery.js"></script>
<script>
/*
Viewer Generation III
Split the API into the following sections:
- main control actions
do main domain tasks like image and ribbon manipulation.
- serialization and deserialization
load and save data
- UI
basic align, animation and modes
*/
function createImage(n){
if(n == null){
if(window._n == null){
window._n = 0
}
n = _n
_n += 1
}
return $('<div order="'+n+'" class="image"/>')
}
function createRibbon(){
return $('<div class="ribbon"/>')
}
// NOTE: if this returns null, it means that the element is smallest in
// target ribbon -- first position.
function getImageBefore(image, ribbon){
image = $(image)
var images = $(ribbon).find('.image')
var order = image.attr('order')
var prev = null
images.each(function(){
if(order < $(this).attr('order')){
return false
}
prev = this
})
return prev
}
function shiftTo(image, ribbon){
var target = getImageBefore(image, ribbon)
var cur_ribbon = image.closest('.ribbon')
// insert before the first image if nothing is before the target...
if(target == null){
image.insertBefore($(ribbon).find('.image').first())
} else {
image.insertAfter(target)
}
// if removing last image out of a ribbon, remove the ribbon....
if(cur_ribbon.find('.image').length == 0){
cur_ribbon.remove()
}
return image
}
function shiftImage(direction, image, force_create_ribbon){
if(image == null){
// XXX need to make this context specific...
image = $('.current.image')
} else {
image = $(image)
}
var ribbon = image.closest('.ribbon')[direction]('.ribbon')
// need to create a new ribbon...
if(ribbon.length == 0 || force_create_ribbon == true){
ribbon = createRibbon()['insert' + (direction == 'prev'
? 'Before'
: 'After')](image.closest('.ribbon'))
ribbon.append(image)
} else {
shiftTo(image, ribbon)
}
return image
}
// short-hand methods...
function shiftImageUp(image){
return shiftImage('prev', image)
}
function shiftImageDown(image){
return shiftImage('next', image)
}
function shiftImageUpNewRibbon(image){
return shiftImage('prev', image, true)
}
function shiftImageDownNewRibbon(image){
return shiftImage('next', image, true)
}
// TODO manual image ordering (shiftLeft/shiftRight functions)
// XXX
// NOTE: this is on purpose done relative...
function clickHandler(evt){
var img = $(evt.target).closest('.image')
img.closest('.viewer').find('.current.image').removeClass('current')
img.addClass('current')
}
// setup...
$(function(){
// populate the viewer...
var r = createRibbon()
var images = []
for(var i=0; i < 40; i++){
images.push(createImage().text(i)[0])
}
r.append($(images))
var rr = r.clone()
var rrr = r.clone()
$('.ribbon-set')
.append(r)
.append(rr)
.append(rrr)
// NOTE: this is global so as to not to add any extra complexity to
// the internal workings...
$('.viewer').click(clickHandler)
})
</script>
</head>
<body>
<!-- This is the basic viewer structure...
Unpopulated
NOTE: there can be only .ribbon-set element.
<div class="viewer">
<div class="ribbon-set"></div>
</div>
Populated
<div class="viewer">
<div class="ribbon-set">
<div class="ribbon">
<div class="image"></div>
<div class="image"></div>
</div>
<div class="ribbon">
<div class="image"></div>
<div class="current image"></div>
<div class="image"></div>
<div class="image"></div>
</div>
</div>
</div>
-->
<div class="viewer">
<div class="ribbon-set"></div>
</div>
<!-- vim:set ts=4 sw=4 spell : -->
</body>
</html>