From 39f9e9bb4d4e7f211ca52fa48a5b7b3e3289fca0 Mon Sep 17 00:00:00 2001 From: j <0x006A@0x2620.org> Date: Tue, 3 Jan 2012 00:36:36 +0530 Subject: [PATCH] implement 'view annotations at position / in selection / all' --- source/Ox.UI/js/List/Ox.List.js | 12 +- source/Ox.UI/js/Menu/Ox.Menu.js | 44 +++++--- source/Ox.UI/js/Menu/Ox.MenuButton.js | 2 +- source/Ox.UI/js/Video/Ox.AnnotationPanel.js | 50 ++++++++- source/Ox.UI/js/Video/Ox.VideoEditor.js | 117 +++++++++++--------- source/Ox.UI/themes/classic/css/classic.css | 7 ++ 6 files changed, 152 insertions(+), 80 deletions(-) diff --git a/source/Ox.UI/js/List/Ox.List.js b/source/Ox.UI/js/List/Ox.List.js index 2a874806..5cfedc9a 100644 --- a/source/Ox.UI/js/List/Ox.List.js +++ b/source/Ox.UI/js/List/Ox.List.js @@ -26,7 +26,7 @@ Ox.List List Element selected ids of the selected elements sort sort order sortable If true, items can be re-ordered - type + type unique name of the key that acts as unique id self shared private variable add item added @@ -442,8 +442,8 @@ Ox.List = function(options, self) { if (self.listLength < visibleItems) { Ox.range(self.listLength, visibleItems).forEach(function(i) { var $item = Ox.ListItem({ - construct: self.options.construct, - }); + construct: self.options.construct, + }); $item.addClass('OxEmpty').removeClass('OxTarget'); if (i == visibleItems - 1) { $item.$element.css({ @@ -1507,7 +1507,7 @@ Ox.List = function(options, self) { }); self.options.items.splice.apply(self.options.items, Ox.merge([pos, 0], items)); self.$items.splice.apply(self.$items, Ox.merge([pos, 0], $items)); - self.listLength += length; + self.listLength = self.options.items.length; //loadItems(); updatePositions(); } @@ -1657,10 +1657,10 @@ Ox.List = function(options, self) { self.selected[i] -= length; } }); - self.listLength -= length; + self.listLength = self.options.items.length; updatePositions(); } - } + } /*@ scrollToSelection scroll list to current selection () -> returns List Element diff --git a/source/Ox.UI/js/Menu/Ox.Menu.js b/source/Ox.UI/js/Menu/Ox.Menu.js index 75b5297a..cd1c6059 100644 --- a/source/Ox.UI/js/Menu/Ox.Menu.js +++ b/source/Ox.UI/js/Menu/Ox.Menu.js @@ -118,7 +118,9 @@ Ox.Menu = function(options, self) { function clickItem(position) { var item = that.items[position], + group = item.options('group'), menu = self.options.mainmenu || self.options.parent || that, + offset, toggled; that.hideMenu(); if (!item.options('items').length) { @@ -126,19 +128,20 @@ Ox.Menu = function(options, self) { self.options.parent.hideMenu(true).triggerEvent('click'); } if (item.options('checked') !== null) { - if (item.options('group')) { - toggled = self.optionGroups[item.options('group')].toggle(position); + if (group) { + offset = self.optionGroupOffset[group]; + toggled = self.optionGroup[group].toggle(position - offset); if (toggled.length) { toggled.forEach(function(pos) { - that.items[pos].toggleChecked(); + that.items[pos + offset].toggleChecked(); }); menu.triggerEvent('change', { id: item.options('group'), - checked: self.optionGroups[item.options('group')].checked().map(function(v) { + checked: self.optionGroup[group].checked().map(function(pos) { return { - id: that.items[v].options('id'), - title: Ox.isString(that.items[v].options('title')[0]) - ? Ox.stripTags(that.items[v].options('title')[0]) : '' + id: that.items[pos + offset].options('id'), + title: Ox.isString(that.items[pos + offset].options('title')[0]) + ? Ox.stripTags(that.items[pos + offset].options('title')[0]) : '' }; }) }); @@ -263,10 +266,13 @@ Ox.Menu = function(options, self) { function renderItems(items) { + var offset = 0; + that.$content.empty(); scrollMenuUp(); - self.optionGroups = {}; + self.optionGroup = {}; + self.optionGroupOffset = {}; items.forEach(function(item, i) { if (item.group) { items[i] = item.items.map(function(v) { @@ -274,13 +280,15 @@ Ox.Menu = function(options, self) { group: item.group }); }); - self.optionGroups[item.group] = new Ox.OptionGroup( + self.optionGroup[item.group] = new Ox.OptionGroup( items[i].filter(function(v) { return 'id' in v; }), 'min' in item ? item.min : 1, 'max' in item ? item.max : 1 ); + self.optionGroupOffset[item.group] = i + offset; + offset += items[i].length - 1; } }); items = Ox.flatten(items); @@ -581,17 +589,23 @@ Ox.Menu = function(options, self) { @*/ that.checkItem = function(id) { Ox.Log('Menu', 'checkItem id', id) - var ids = id.split('_'), - item; + var group, + ids = id.split('_'), + item, + offset, + position, + toggled; if (ids.length == 1) { item = that.getItem(id); + group = item.options('group'); Ox.Log('Menu', 'checkItem', id, item, that.submenus) - if (item.options('group')) { - var position = getItemPositionById(id), - toggled = self.optionGroups[item.options('group')].toggle(position); + if (group) { + offset = self.optionGroupOffset[group]; + position = getItemPositionById(id); + toggled = self.optionGroup[item.options('group')].toggle(position - offset); if (toggled.length) { toggled.forEach(function(pos) { - that.items[pos].toggleChecked(); + that.items[pos + offset].toggleChecked(); }); } } else { diff --git a/source/Ox.UI/js/Menu/Ox.MenuButton.js b/source/Ox.UI/js/Menu/Ox.MenuButton.js index 20951fa3..f460a3d7 100644 --- a/source/Ox.UI/js/Menu/Ox.MenuButton.js +++ b/source/Ox.UI/js/Menu/Ox.MenuButton.js @@ -85,7 +85,7 @@ Ox.MenuButton = function(options, self) { } function changeMenu(data) { - that.triggerEvent('click', data); + that.triggerEvent('change', data); } function hideMenu(data) { diff --git a/source/Ox.UI/js/Video/Ox.AnnotationPanel.js b/source/Ox.UI/js/Video/Ox.AnnotationPanel.js index 944f8c7e..9d0a65b1 100644 --- a/source/Ox.UI/js/Video/Ox.AnnotationPanel.js +++ b/source/Ox.UI/js/Video/Ox.AnnotationPanel.js @@ -8,6 +8,7 @@ Ox.AnnotationPanel AnnotationPanel Object (options) -> AnnotationPanel Object (options, self) -> AnnotationPanel Object options Options object + editable If true, annotations can be added id id items items title title @@ -21,8 +22,10 @@ Ox.AnnotationPanel = function(options, self) { self = self || {}; var that = Ox.Element({}, self) .defaults({ + editable: false, id: '', items: [], + range: 'all', title: '', type: 'text', width: 0 @@ -31,7 +34,8 @@ Ox.AnnotationPanel = function(options, self) { self.selected = -1; - that.$element = Ox.CollapsePanel({ + that.setElement( + Ox.CollapsePanel({ collapsed: false, extras: self.options.editable ? [ Ox.Button({ @@ -52,7 +56,8 @@ Ox.AnnotationPanel = function(options, self) { .addClass('OxAnnotationPanel') .bindEvent({ toggle: togglePanel - }); + }) + ); that.$content = that.$element.$content; self.$annotations = Ox.List({ @@ -78,8 +83,11 @@ Ox.AnnotationPanel = function(options, self) { .append($('
').css({height: '4px'})); return $item; }, - items: self.options.items, + items: getAnnotations(), max: 1, + min: 0, + sort: [{key: 'in', operator: '+'}], + type: 'none', // fixme unique: 'id' }) .bindEvent({ @@ -116,6 +124,21 @@ Ox.AnnotationPanel = function(options, self) { .appendTo(self.$annotations); }); */ + + function getAnnotations() { + return self.options.items.filter(function(item) { + return self.options.range == 'all' || ( + self.options.range == 'selection' + && item['in'] < self.options.out + && item.out > self.options['in'] + ) || ( + self.options.range == 'position' + && item['in'] <= self.options.position + && item.out > self.options.position + ); + }); + } + function selectAnnotation(data) { var item = Ox.getObjectById(self.options.items, data.ids[0]); item && that.triggerEvent('select', { @@ -124,6 +147,7 @@ Ox.AnnotationPanel = function(options, self) { 'layer': self.options.id }); } + function updateAnnotation(data) { var item = Ox.getObjectById(self.options.items, data.id); item.value = data.value; @@ -134,6 +158,26 @@ Ox.AnnotationPanel = function(options, self) { } + self.setOption = function(key, value) { + if (key == 'in') { + self.options.range == 'selection' && self.$annotations.options({ + items: getAnnotations() + }); + } else if (key == 'out') { + self.options.range == 'selection' && self.$annotations.options({ + items: getAnnotations() + }); + } else if (key == 'position') { + self.options.range == 'position' && self.$annotations.options({ + items: getAnnotations() + }); + } else if (key == 'range') { + self.$annotations.options({ + items: getAnnotations() + }); + } + }; + /*@ addItem addItem @*/ diff --git a/source/Ox.UI/js/Video/Ox.VideoEditor.js b/source/Ox.UI/js/Video/Ox.VideoEditor.js index fbad0598..a3bbc227 100644 --- a/source/Ox.UI/js/Video/Ox.VideoEditor.js +++ b/source/Ox.UI/js/Video/Ox.VideoEditor.js @@ -18,6 +18,8 @@ Ox.VideoEditor = function(options, self) { self = self || {}; var that = Ox.Element({}, self) .defaults({ + annotationsFont: 'small', + annotationsRange: 'all', annotationsSize: 0, censored: [], cuts: [], @@ -214,10 +216,11 @@ Ox.VideoEditor = function(options, self) { paused: function(data) { that.triggerEvent('paused', data); }, - playing: changePlayer, + playing: function(data) { + setPosition(data.position, true); + }, position: function(data) { - changePlayer(data); - that.triggerEvent('position', data); + setPosition(data.position); }, resolution: function(data) { that.triggerEvent('resolution', data); @@ -262,7 +265,9 @@ Ox.VideoEditor = function(options, self) { top: self.sizes.timeline[0].top + 'px' }) .bindEvent({ - position: changeTimelineLarge + position: function(data) { + setPosition(data.position); + } }) .appendTo(self.$editor); @@ -287,7 +292,9 @@ Ox.VideoEditor = function(options, self) { top: self.sizes.timeline[1].top + 'px', }) .bindEvent({ - position: changeTimelineSmall + position: function(data) { + setPosition(data.position); + } }) .appendTo(self.$editor); @@ -300,6 +307,11 @@ Ox.VideoEditor = function(options, self) { self.options.layers.forEach(function(layer, i) { self.$annotationPanel[i] = Ox.AnnotationPanel( Ox.extend({ + font: self.options.annotationsFont, + 'in': self.options['in'], + out: self.options.out, + position: self.options.position, + range: self.options.annotationsRange, width: self.options.annotationsSize - Ox.UI.SCROLLBAR_SIZE }, layer) ) @@ -419,6 +431,7 @@ Ox.VideoEditor = function(options, self) { {id: 'keyboard', title: 'Keyboard Shortcuts...', keyboard: 'h'} ] ), + style: 'square', title: 'set', tooltip: 'Actions and Settings', type: 'image' @@ -621,22 +634,36 @@ Ox.VideoEditor = function(options, self) { self.$annotationsMenuButton = Ox.MenuButton({ items: [ - {id: 'annotations', title: 'Show Annotations', disabled: true}, - {id: 'showAnnotationsAtPosition', title: 'At Current Position', checked: true}, - {id: 'showAnnotationsInSelection', title: 'In Current Selection'}, - {id: 'showAllAnnotations', title: 'All'}, + {id: 'showannotations', title: 'Show Annotations', disabled: true}, + {group: 'range', min: 1, max: 1, items: [ + {id: 'position', title: 'At Current Position', checked: self.options.annotationsRange == 'position'}, + {id: 'selection', title: 'In Current Selection', checked: self.options.annotationsRange == 'selection'}, + {id: 'all', title: 'All', checked: self.options.annotationsRange == 'all'} + ]}, {}, - {id: 'textSize', title: 'Font Size', disabled: true}, - {id: 'smallText', title: 'Small', checked: true}, - {id: 'mediumText', title: 'Medium'}, - {id: 'largeText', title: 'Large'} + {id: 'fontsize', title: 'Font Size', disabled: true}, + {group: 'font', min: 1, max: 1, items: [ + {id: 'small', title: 'Small', checked: self.options.annotationsFont == 'small'}, + {id: 'medium', title: 'Medium', checked: self.options.annotationsFont == 'medium'}, + {id: 'large', title: 'Large', checked: self.options.annotationsFont == 'large'} + ]} ], - max: 2, + style: 'square', title: 'set', tooltip: 'Actions and Settings', type: 'image' }) .css({float: 'left'}) + .bindEvent({ + change: function(data) { + var set = {}; + set[data.id] = data.checked[0].id; + self.$annotationPanel.forEach(function($panel) { + $panel.options(set); + }); + that.triggerEvent('annotations' + Ox.toTitleCase(data.id), set); + } + }) .appendTo(self.$annotationsbar); that.$element = Ox.SplitPanel({ @@ -672,6 +699,7 @@ Ox.VideoEditor = function(options, self) { }) .bindEvent({ resize: resizeAnnotations, + resizeend: resizeendAnnotations, toggle: toggleAnnotations }), resizable: true, @@ -689,42 +717,6 @@ Ox.VideoEditor = function(options, self) { submitFindInput(self.options.find, true); }, 0); - function changePlayer(data) { - self.options.position = data.position; - self.$timeline[0].options({ - position: data.position - }); - self.$timeline[1].options({ - position: data.position - }); - } - - function changeTimelineLarge(data) { - self.options.position = data.position; - self.$player[0].options({ - position: data.position - }); - self.$timeline[1].options({ - position: data.position - }); - that.triggerEvent('position', { - position: self.options.position - }); - } - - function changeTimelineSmall(data) { - self.options.position = data.position; - self.$player[0].options({ - position: data.position - }); - self.$timeline[0].options({ - position: data.position - }); - that.triggerEvent('position', { - position: self.options.position - }); - } - function find(query) { var results = []; if (query.length) { @@ -888,6 +880,10 @@ Ox.VideoEditor = function(options, self) { setSizes(); } + function resizeendAnnotations(data) { + that.triggerEvent('annotationsSize', {size: data.size}); + } + function resizeEditor(data) { var width = data.size - 2 * margin + 100; resizeVideoPlayers(width); @@ -943,23 +939,34 @@ Ox.VideoEditor = function(options, self) { if (self.options['in'] > self.options.out) { setPoint(point == 'in' ? 'out' : 'in', position); } + self.$annotationPanel.forEach(function($panel) { + $panel.options({ + 'in': self.options['in'], + out: self.options.out + }); + }); that.triggerEvent('points', { 'in': self.options['in'], out: self.options.out }); } - function setPosition(position) { + function setPosition(position, playing) { self.options.position = position; - self.$player[0].options({ + !playing && self.$player[0].options({ position: self.options.position }); - self.$timeline.forEach(function(v) { - v.options({ + self.$timeline.forEach(function($timeline) { + $timeline.options({ position: self.options.position }); }); - that.triggerEvent('position', { + self.$annotationPanel.forEach(function($panel) { + $panel.options({ + position: self.options.position + }); + }); + !playing && that.triggerEvent('position', { position: self.options.position }); } diff --git a/source/Ox.UI/themes/classic/css/classic.css b/source/Ox.UI/themes/classic/css/classic.css index f41181f1..f19f073b 100644 --- a/source/Ox.UI/themes/classic/css/classic.css +++ b/source/Ox.UI/themes/classic/css/classic.css @@ -668,6 +668,13 @@ Video ================================================================================ */ +.OxThemeClassic .OxAnnotation { + border-color: rgb(208, 208, 208); +} +.OxThemeClassic .OxAnnotation.OxSelected { + background: rgb(208, 208, 208); +} + .OxThemeClassic .OxSmallVideoTimeline .OxMarkerPlay { border-color: rgba(0, 0, 0, 0.5); }