mirror of
				https://github.com/flynx/ImageGrid.git
				synced 2025-11-04 05:10:07 +00:00 
			
		
		
		
	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:
		
							parent
							
								
									226140de06
								
							
						
					
					
						commit
						00151937ff
					
				
							
								
								
									
										61
									
								
								ui/Gen3-TODO.otl
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										61
									
								
								ui/Gen3-TODO.otl
									
									
									
									
									
										Executable 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
									
								
							
							
						
						
									
										153
									
								
								ui/ImageGrid.js
									
									
									
									
									
										Executable 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
									
								
							
							
						
						
									
										269
									
								
								ui/index.html
									
									
									
									
									
										Executable 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>
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user