/*
* Copyright 2020 WICKLETS LLC
*
* This file is part of Wick Engine.
*
* Wick Engine is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Wick Engine is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Wick Engine. If not, see <https://www.gnu.org/licenses/>.
*/
Wick.View.Clip = class extends Wick.View {
static get BORDER_STROKE_WIDTH () {
return 2;
}
static get BORDER_STROKE_COLOR_NORMAL () {
return '#2636E1';
}
static get BORDER_STROKE_COLOR_HAS_CODE () {
return '#01C094';
}
static get BORDER_STROKE_COLOR_HAS_CODE_ERROR () {
return '#E61E07';
}
static get PLACEHOLDER_SIZE () {
return 10;
}
/**
* Creates a new Button view.
*/
constructor () {
super();
this.group = new this.paper.Group();
this.group.remove();
this.group.applyMatrix = false;
this._bounds = new paper.Rectangle();
//this._radius = null;
}
get bounds () {
return this._bounds;
}
get absoluteBounds () {
return this.group.bounds;
}
// get radius () {
// if (this._radius) {
// return this._radius;
// }
// let center = this.absoluteBounds.center;
// let convert = (point) => point.getDistance(center, true);
// let compare = (a, b) => Math.max(a,b);
// let initial = 0;
// this._radius = Math.sqrt(this.reducePointsFromGroup(this.group, initial, convert, compare));
// return this._radius;
// }
// get convexHull () {
// let group = this.group;
// let initial = [];
// let convert = (point) => [[point.x, point.y]];
// let compare = (list1, list2) => list1.concat(list2);
// let points = this.reducePointsFromGroup(group, initial, convert, compare);
// // Infinity gets us the convex hull
// let ch = hull(points, Infinity);
// let removedDuplicates = [];
// let epsilon = 0.01;
// for (let i = 0; i < ch.length; i++) {
// if (removedDuplicates.length > 0) {
// if ((Math.abs(ch[i][0] - removedDuplicates[removedDuplicates.length - 1][0]) > epsilon ||
// Math.abs(ch[i][1] - removedDuplicates[removedDuplicates.length - 1][1]) > epsilon) &&
// (Math.abs(ch[i][0] - removedDuplicates[0][0]) > epsilon ||
// Math.abs(ch[i][1] - removedDuplicates[0][1]) > epsilon)) {
// removedDuplicates.push(ch[i]);
// }
// }
// else {
// removedDuplicates.push(ch[i]);
// }
// }
// return removedDuplicates;
// }
get points () {
let group = this.group;
let initial = [];
let convert = (point) => [[point.x, point.y]];
let compare = (list1, list2) => list1.concat(list2);
return this.reducePointsFromGroup(group, initial, convert, compare);
}
// group: the paper group of objects
// initial: the initial value, should be of return type
// convert: point -> return type
// compare: (return type, return type) -> return type
reducePointsFromGroup (group, initial, convert, compare) {
let val = initial;
for (let i = 0; i < group.children.length; i++) {
let child = group.children[i];
if (child.className === 'Layer') {
let ch = child.children;
for (let j = 0; j < ch.length; j++) {
let item = ch[j];
if (item.className === 'Path') {
let matrix = item.globalMatrix;
for (let s = 0; s < item.segments.length; s++) {
val = compare(val, convert(matrix.transform(item.segments[s].point)));
}
}
else if (item.className === 'CompoundPath') {
for (let p = 0; p < item.children.length; p++) {
let path = item.children[p];
let matrix = item.globalMatrix;
for (let s = 0; s < path.segments.length; s++) {
val = compare(val, convert(matrix.transform(path.segments[s].point)));
}
}
}
else if (item.className === 'Group') {
val = compare(val, this.reducePointsFromGroup(item));
}
}
}
}
return val;
}
render () {
// Prevent an unselectable object from being rendered
// due to a clip having no content on the first frame.
this.model.ensureActiveFrameIsContentful();
// Render timeline view
this.model.timeline.view.render();
// Add some debug info to the paper group
this.group.data.wickType = 'clip';
this.group.data.wickUUID = this.model.uuid;
// Add frame views from timeline
this.group.removeChildren();
this.group.addChildren(this.model.timeline.view.frameLayers);
// Update transformations
this.group.matrix.set(new paper.Matrix());
this._bounds = this.group.bounds.clone();
//this._radius = null;
this.group.pivot = new this.paper.Point(0,0);
this.group.position.x = this.model.transformation.x;
this.group.position.y = this.model.transformation.y;
this.group.scaling.x = this.model.transformation.scaleX;
this.group.scaling.y = this.model.transformation.scaleY;
this.group.rotation = this.model.transformation.rotation;
this.group.opacity = this.model.transformation.opacity;
}
generateBorder () {
var group = new this.paper.Group({insert:false});
group.locked = true;
group.data.wickType = 'clip_border_' + this.model.uuid;
var bounds = this.bounds;
// Change border colors based on if the Clip caused an error
var strokeColor = Wick.View.Clip.BORDER_STROKE_COLOR_NORMAL;
if(this.model.project.error && this.model.project.error.uuid === this.model.uuid) {
strokeColor = Wick.View.Clip.BORDER_STROKE_COLOR_HAS_CODE_ERROR;
} else if(this.model.hasContentfulScripts) {
strokeColor = Wick.View.Clip.BORDER_STROKE_COLOR_HAS_CODE;
}
var border = new paper.Path.Rectangle({
name: 'border',
from: bounds.topLeft,
to: bounds.bottomRight,
strokeWidth: Wick.View.Clip.BORDER_STROKE_WIDTH / this.paper.view.zoom,
strokeColor: strokeColor,
insert: false,
});
group.addChild(border);
group.pivot = new this.paper.Point(0,0);
group.position.x = this.model.transformation.x;
group.position.y = this.model.transformation.y;
group.scaling.x = this.model.transformation.scaleX;
group.scaling.y = this.model.transformation.scaleY;
group.rotation = this.model.transformation.rotation;
return group;
}
}