Remove global views list, link View to Project and allow projects to only have one view.

This commit is contained in:
Jürg Lehni 2011-11-12 16:56:23 +01:00
parent ea689faa43
commit 719ae2315c
4 changed files with 93 additions and 118 deletions

View file

@ -49,8 +49,6 @@ var PaperScope = this.PaperScope = Base.extend(/** @lends PaperScope# */{
// Whenever a PaperScope is created, it automatically becomes the active
// one.
paper = this;
this.view = null;
this.views = [];
this.project = null;
this.projects = [];
this.tool = null;
@ -87,16 +85,13 @@ var PaperScope = this.PaperScope = Base.extend(/** @lends PaperScope# */{
*/
/**
* The active view of the active project.
* The reference to the active project's view.
* @name PaperScope#view
* @type View
*/
/**
* The list of view of the active project.
* @name PaperScope#views
* @type View[]
*/
getView: function() {
return this.project.view;
},
/**
* The reference to the active tool.
@ -159,19 +154,14 @@ var PaperScope = this.PaperScope = Base.extend(/** @lends PaperScope# */{
// Make sure this is the active scope, so the created project and view
// are automatically associated with it.
paper = this;
this.project = new Project();
// Create a view for the canvas.
if (canvas)
this.view = new View(canvas);
this.project = new Project(canvas);
},
clear: function() {
// Remove all projects, views and tools.
// This also removes the installed event handlers.
for (var i = this.projects.length - 1; i >= 0; i--)
this.projects[i].remove();
// This also removes the installed event handlers.
for (var i = this.views.length - 1; i >= 0; i--)
this.views[i].remove();
for (var i = this.tools.length - 1; i >= 0; i--)
this.tools[i].remove();
},
@ -181,15 +171,6 @@ var PaperScope = this.PaperScope = Base.extend(/** @lends PaperScope# */{
delete PaperScope._scopes[this._id];
},
_needsRedraw: function() {
// Make sure we're not looping through the view list each time...
if (!this._redrawNotified) {
for (var i = this.views.length - 1; i >= 0; i--)
this.views[i]._redrawNeeded = true;
this._redrawNotified = true;
}
},
statics: /** @lends PaperScope */{
_scopes: {},
_id: 0,
@ -205,16 +186,6 @@ var PaperScope = this.PaperScope = Base.extend(/** @lends PaperScope# */{
if (typeof id === 'object')
id = id.getAttribute('id');
return this._scopes[id] || null;
},
/**
* Iterates over all active scopes and calls the passed iterator
* function for each of them.
*
* @param iter the iterator function.
*/
each: function(iter) {
Base.each(this._scopes, iter);
}
}
});

View file

@ -34,17 +34,11 @@
*/
/**
* The active view of the active project.
* The reference to the active project's view.
* @name view
* @type View
*/
/**
* The list of view of the active project.
* @name views
* @type View[]
*/
/**
* The reference to the active tool.
* @name tool

View file

@ -44,10 +44,13 @@ var Project = this.Project = PaperScopeItem.extend(/** @lends Project# */{
*
* When working with PaperScript, a project is automatically created for us
* and the {@link PaperScope#project} variable points to it.
*
* @param {View|HTMLCanvasElement} view Either a view object or an HTML
* Canvas element that should be wrapped in a newly created view.
*/
initialize: function() {
// Activate straight away so paper.project is set, as required by
// Layer and DoumentView constructors.
initialize: function(view) {
// Activate straight away by passing true to base(), so paper.project is
// set, as required by Layer and DoumentView constructors.
this.base(true);
this._currentStyle = new PathStyle();
this._selectedItems = {};
@ -55,14 +58,16 @@ var Project = this.Project = PaperScopeItem.extend(/** @lends Project# */{
this.layers = [];
this.symbols = [];
this.activeLayer = new Layer();
if (view)
this.view = view instanceof View ? view : View.create(view);
// Change tracking, not in use for now. Activate once required:
// this._changes = [];
// this._changesById = {};
},
_needsRedraw: function() {
if (this._scope)
this._scope._needsRedraw();
if (this.view)
this.view._redrawNeeded = true;
},
/**
@ -74,10 +79,21 @@ var Project = this.Project = PaperScopeItem.extend(/** @lends Project# */{
*/
/**
* Removes this project from the {@link PaperScope#projects} list.
*
* @name Project#remove
* @function
* Removes this project from the {@link PaperScope#projects} list, and also
* removes its view, if one was defined.
*/
remove: function() {
if (!this.base())
return false;
if (this.view)
this.view.remove();
return true;
},
/**
* The reference to the project's view.
* @name Project#view
* @type View
*/
/**

View file

@ -23,9 +23,7 @@
* center, both useful for constructing artwork that should appear centered on
* screen.
*/
var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
_list: 'views',
_reference: 'view',
var View = this.View = Base.extend(Callback, /** @lends View# */{
_events: {
onFrame: {
install: function() {
@ -79,15 +77,18 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
},
/**
* Creates a view object
* @param {HTMLCanvasElement|String} canvas The canvas object that this
* view should wrap, or the String id that represents it
* Creates a view object for a given project.
*
* @param {HTMLCanvasElement} canvas The canvas object that this view should
* wrap
*/
initialize: function(canvas) {
this.base();
// Store reference to the currently active global paper scope, and the
// active project, which will be represented by this view
this._scope = paper;
this._project = paper.project;
// Handle canvas argument
var size;
/*#*/ if (options.server) {
if (canvas && canvas instanceof Canvas) {
this._canvas = canvas;
@ -104,11 +105,7 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
this._id = this._canvas.id;
if (this._id == null)
this._canvas.id = this._id = 'canvas-' + View._id++;
/*#*/ } // options.server
/*#*/ if (options.browser) {
if (typeof canvas === 'string')
canvas = document.getElementById(canvas);
/*#*/ } else if (options.browser) {
if (canvas instanceof HTMLCanvasElement) {
this._canvas = canvas;
// If the canvas has the resize attribute, resize the it to fill the
@ -163,51 +160,42 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
this._id = this._canvas.getAttribute('id');
if (this._id == null)
this._canvas.setAttribute('id', this._id = 'canvas-' + View._id++);
// Install event handlers
this._handlers = this._createHandlers();
DomEvent.add(this._canvas, this._handlers);
/*#*/ } // options.browser
// Keep track of views internally
View._views.push(this);
// Link this id to our view
View._views[this._id] = this;
View._viewsById[this._id] = this;
this._viewSize = LinkedSize.create(this, 'setViewSize',
size.width, size.height);
this._context = this._canvas.getContext('2d');
this._matrix = new Matrix();
this._zoom = 1;
/*#*/ if (options.browser) {
this._domEvents = this._createEvents();
DomEvent.add(this._canvas, this._domEvents);
// Make sure the first view is focused for keyboard input straight away
if (!View._focused)
View._focused = this;
/*#*/ } // options.browser
// As soon as a new view is added we need to mark the redraw as not
// motified, so the next call loops through all the views again.
this._scope._redrawNotified = false;
},
/**
* Makes this view the active one, meaning {@link PaperScope#view} will
* point to it.
*
* @name View#activate
* @function
*/
/**
* Removes thsi view from the {@link PaperScope#views} list and frees the
* associated canvas.
* Removes this view from and frees the associated canvas.
*/
remove: function() {
if (!this.base())
if (!this._project)
return false;
// Clear focus if removed view had it
if (View._focused == this)
View._focused = null;
delete View._views[this._id];
// Remove view from internal structures
View._views.splice(View._views.indexOf(this), 1);
delete View._viewsById[this._id];
// Unlink from project
if (this._project.view == this)
this._project.view = null;
// Uninstall event handlers again for this view.
DomEvent.remove(this._canvas, this._domEvents);
this._canvas = this._domEvents = null;
DomEvent.remove(this._canvas, this._handlers);
this._canvas = this._project = this._handlers = null;
// Removing all onFrame handlers makes the _onFrameCallback handler stop
// automatically through its uninstall method.
this.detach('frame');
@ -324,7 +312,8 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
setZoom: function(zoom) {
// TODO: Clamp the view between 1/32 and 64, just like Illustrator?
this._transform(new Matrix().scale(zoom / this._zoom, this.getCenter()));
this._transform(new Matrix().scale(zoom / this._zoom,
this.getCenter()));
this._zoom = zoom;
},
@ -367,14 +356,9 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
ctx.save();
this._matrix.applyToContext(ctx);
// Just draw the active project for now
this._scope.project.draw(ctx);
this._project.draw(ctx);
ctx.restore();
if (this._redrawNeeded) {
this._redrawNeeded = false;
// Update _redrawNotified in PaperScope as soon as a view was drawn
this._scope._redrawNotified = false;
}
this._redrawNeeded = false;
return true;
},
@ -405,11 +389,12 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
* The function receives an event object which contains information about
* the frame event:
*
* <b>{@code event.count}</b>: the number of times the frame event was fired.
* <b>{@code event.time}</b>: the total amount of time passed since the first frame
* event in seconds.
* <b>{@code event.delta}</b>: the time passed in seconds since the last frame
* event.
* <b>{@code event.count}</b>: the number of times the frame event was
* fired.
* <b>{@code event.time}</b>: the total amount of time passed since the
* first frame event in seconds.
* <b>{@code event.delta}</b>: the time passed in seconds since the last
* frame event.
*
* @example {@paperscript}
* // Creating an animation:
@ -450,8 +435,19 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
*/
}, {
statics: {
_views: {},
_id: 0
_views: [],
_viewsById: {},
_id: 0,
create: function(element) {
/*#*/ if (options.browser) {
if (typeof element === 'string')
element = document.getElementById(element);
/*#*/ } // options.browser
// Factory to provide the right View subclass for a given element.
// Produces only Canvas-Views for now:
return new View(element);
}
}
}, new function() {
// Injection scope for special code on browser (mouse events)
@ -469,16 +465,14 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
function updateFocus() {
if (!View._focused || !View._focused.isVisible()) {
// Find the first visible view in all scopes
PaperScope.each(function(scope) {
for (var i = 0, l = scope.views.length; i < l; i++) {
var view = scope.views[i];
if (view.isVisible()) {
View._focused = tempFocus = view;
throw Base.stop;
}
// Find the first visible view
for (var i = 0, l = View._views.length; i < l; i++) {
var view = View._views[i];
if (view && view.isVisible()) {
View._focused = tempFocus = view;
throw Base.stop;
}
});
}
}
}
@ -487,7 +481,7 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
if (!dragging) {
// See if we can get the view from the current event target, and
// handle the mouse move over it.
view = View._views[DomEvent.getTarget(event).getAttribute('id')];
view = View._viewsById[DomEvent.getTarget(event).getAttribute('id')];
if (view) {
// Temporarily focus this view without making it sticky, so
// Key events are handled too during the mouse over
@ -526,7 +520,8 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
if (tool) {
if (timer != null)
timer = clearInterval(timer);
if (tool.onHandleEvent('mouseup', viewToProject(view, event), event)) {
if (tool.onHandleEvent('mouseup', viewToProject(view, event),
event)) {
view.draw(true);
DomEvent.stop(event);
}
@ -543,7 +538,7 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
// mousemove and mouseup events need to be installed on document, not the
// view canvas, since we want to catch the end of drag events even outside
// our view. Only the mousedown events are installed on the view, as handled
// by _createEvents below.
// by _createHandlers below.
DomEvent.add(document, {
mousemove: mousemove,
@ -559,7 +554,7 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
});
return {
_createEvents: function() {
_createHandlers: function() {
var view = this;
function mousedown(event) {
@ -583,7 +578,6 @@ var View = this.View = PaperScopeItem.extend(Callback, /** @lends View# */{
},
statics: {
/**
* Loops through all scopes and their views and sets the focus on
* the first active one.