Browse Source

FXScene: Fix dopesheet sync, preview range

trethaller 7 years ago
parent
commit
9ed3fd1c67
4 changed files with 126 additions and 25 deletions
  1. 30 2
      bin/style.css
  2. 39 3
      bin/style.less
  3. 9 0
      hide/comp/CurveEditor.hx
  4. 48 20
      hide/view/FXScene.hx

+ 30 - 2
bin/style.css

@@ -482,6 +482,7 @@ input[type=checkbox]:checked:after {
 .hide-curve-editor .graph .handles circle,
 .hide-curve-editor .graph .handles rect {
   fill: rgba(187, 187, 187, 0.644);
+  cursor: pointer;
 }
 .hide-curve-editor .graph .handles circle:hover,
 .hide-curve-editor .graph .handles rect:hover {
@@ -517,7 +518,7 @@ input[type=checkbox]:checked:after {
   height: 100%;
 }
 .fx-animpanel .timeline {
-  background: #000;
+  background: #141414;
   position: relative;
   height: 20px;
   overflow: hidden;
@@ -546,7 +547,7 @@ input[type=checkbox]:checked:after {
   height: 100%;
   overflow: hidden;
 }
-.fx-animpanel .overlay-container .overlay .line {
+.fx-animpanel .overlay-container .overlay .timeline {
   position: absolute;
   height: 100%;
   width: 1px;
@@ -560,6 +561,30 @@ input[type=checkbox]:checked:after {
   border-left: 1px black;
   border-right: 1px black;
 }
+.fx-animpanel .overlay-container .overlay .preview {
+  position: absolute;
+  height: 20px;
+  background: rgba(255, 255, 255, 0.1);
+  opacity: 0.9;
+  mix-blend-mode: screen;
+  border-left: 1px black;
+  border-right: 1px black;
+}
+.fx-animpanel .overlay-container .overlay .preview-left {
+  background: rgba(255, 255, 255, 0.068);
+  border-left: 1px solid rgba(255, 255, 255, 0.671);
+  position: absolute;
+  height: 100%;
+  width: 4px;
+}
+.fx-animpanel .overlay-container .overlay .preview-right {
+  background: rgba(255, 255, 255, 0.068);
+  border-right: 1px solid rgba(255, 255, 255, 0.671);
+  position: absolute;
+  height: 100%;
+  width: 4px;
+  margin-left: -4px;
+}
 .fx-animpanel .track .track-header {
   height: 20px;
   display: flex;
@@ -573,6 +598,7 @@ input[type=checkbox]:checked:after {
   padding-right: 4px;
 }
 .fx-animpanel .track .track-header .track-prop .track-toggle {
+  cursor: pointer;
   width: 16px;
   height: 16px;
   display: inline-block;
@@ -590,6 +616,8 @@ input[type=checkbox]:checked:after {
   overflow: hidden;
 }
 .fx-animpanel .track .track-header .dopesheet .key {
+  cursor: pointer;
+  user-select: none;
   position: absolute;
   width: 5px;
   margin-top: 1px;

+ 39 - 3
bin/style.less

@@ -535,6 +535,7 @@ input[type=checkbox] {
 		.handles {
 			circle, rect {
 				fill: rgba(187, 187, 187, 0.644);
+				cursor: pointer;
 			}
 			circle:hover, rect:hover {
 				fill: #fff;
@@ -575,9 +576,9 @@ input[type=checkbox] {
 	}
 
 	.timeline {
-		background: #000;
+		background: rgb(20, 20, 20);
 		position: relative;
-		height: 20px;
+		height: @timelineHeight;
 		overflow: hidden;
 
 		.mark {
@@ -604,7 +605,7 @@ input[type=checkbox] {
 			width: 100%;
 			height: 100%;
 			overflow: hidden;
-			.line {
+			.timeline {
 				position: absolute;
 				height: 100%;
 				width: 1px;
@@ -618,6 +619,38 @@ input[type=checkbox] {
 				border-left: 1px black;
 				border-right: 1px black;
 			}
+			.preview {
+				position: absolute;
+				height: @timelineHeight;
+				background: rgba(255, 255, 255, 0.1);
+				opacity: 0.9;
+				//-webkit-filter: invert(100%);
+				mix-blend-mode: screen;
+				// mix-blend-mode: screen;
+				border-left: 1px black;
+				border-right: 1px black;
+			}
+			.preview-left {
+				background: rgba(255, 255, 255, 0.068);
+				//background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0.123), rgba(255, 255, 255, 0));
+				border-left:1px solid rgba(255, 255, 255, 0.671);
+				position: absolute;
+				height: 100%;
+				width: 4px;
+			}
+			.preview-right {
+				background: rgba(255, 255, 255, 0.068);
+				//background: -webkit-linear-gradient(left, rgba(255, 255, 255, 0.123), rgba(255, 255, 255, 0));
+				border-right:1px solid rgba(255, 255, 255, 0.671);
+				position: absolute;
+				height: 100%;
+				width: 4px;
+				margin-left: -4px;
+			}
+			
+			// .preview-left::after {
+			// 	background: url(http://placehold.it/16x16) no-repeat;
+			// }
 		}
 	}
 
@@ -636,6 +669,7 @@ input[type=checkbox] {
 				}
 
 				.track-toggle {
+					cursor: pointer;
 					width: 16px;
 					height: 16px;
 					display: inline-block;
@@ -653,6 +687,8 @@ input[type=checkbox] {
 				box-shadow: 0px -1px 0px black inset;
 				overflow: hidden;
 				.key {
+					cursor: pointer;
+					user-select: none;
 					position: absolute;
 					width: 5px;
 					margin-top: 1px;

+ 9 - 0
hide/comp/CurveEditor.hx

@@ -100,6 +100,10 @@ class CurveEditor extends Component {
 		});
 	}
 
+	public dynamic function onChange(anim: Bool) {
+
+	}
+
 	function set_curve(curve) {
 		this.curve = curve;
 		lastValue = haxe.Json.parse(haxe.Json.stringify(curve.save()));
@@ -285,8 +289,10 @@ class CurveEditor extends Component {
 			lastValue = haxe.Json.parse(haxe.Json.stringify(curve.save()));
 			selectedKeys = [];
 			refresh();
+			onChange(false);
 		}));
 		refresh();
+		onChange(false);
 	}
 
 	public function refresh(?anim: Bool) {
@@ -417,6 +423,7 @@ class CurveEditor extends Component {
 						key.value = nky;
 						fixKey(key);
 						refreshGraph(true, key);
+						onChange(true);
 					}, function(e) {
 						selectedKeys = [key];
 						fixKey(key);
@@ -482,6 +489,7 @@ class CurveEditor extends Component {
 						}
 						fixKey(key);
 						refreshGraph(true, key);
+						onChange(true);
 					}, function(e) {
 						afterChange();
 					});
@@ -523,6 +531,7 @@ class CurveEditor extends Component {
 						lastX = e.clientX;
 						lastY = e.clientY;
 						refreshGraph(true);
+						onChange(true);
 					}, function(e) {
 						afterChange();
 					});

+ 48 - 20
hide/view/FXScene.hx

@@ -89,9 +89,11 @@ class FXScene extends FileView {
 	var currentTime : Float;
 	var selectMin : Float;
 	var selectMax : Float;
+	var previewMin : Float;
+	var previewMax : Float;
 	var curveEdits : Array<hide.comp.CurveEditor>;
 	var timeLineEl : Element;
-	var panCallbacks : Array<Bool->Void>;
+	var refreshDopesheetKeys : Array<Bool->Void> = [];
 
 	override function getDefaultContent() {
 		return haxe.io.Bytes.ofString(ide.toJSON(new hide.prefab.fx.FXScene().save()));
@@ -210,6 +212,8 @@ class FXScene extends FileView {
 
 		selectMin = 0.6;
 		selectMax = 3.2;
+		previewMin = 0.6;
+		previewMax = 3.2;
 		refreshTimeline(false);
 	}
 
@@ -267,18 +271,25 @@ class FXScene extends FileView {
 
 		var overlay = root.find(".overlay");
 		overlay.empty();
-		timeLineEl = new Element('<span class="line"></span>').appendTo(overlay);
+		timeLineEl = new Element('<span class="timeline"></span>').appendTo(overlay);
 		timeLineEl.css({left: xt(currentTime)});
 
 		var select = new Element('<span class="selection"></span>').appendTo(overlay);
 		select.css({left: xt(selectMin), width: xt(selectMax) - xt(selectMin)});
+
+		var preview = new Element('<span class="preview"></span>').appendTo(overlay);
+		preview.css({left: xt(previewMin), width: xt(previewMax) - xt(previewMin)});
+		var prevLeft = new Element('<span class="preview-left"></span>').appendTo(overlay);
+		prevLeft.css({left: xt(previewMin)});
+		var prevRight = new Element('<span class="preview-right"></span>').appendTo(overlay);
+		prevRight.css({left: xt(previewMax)});
 	}
 
 	function afterPan(anim: Bool) {
 		for(curve in curveEdits) {
 			curve.setPan(xOffset, curve.yOffset);
 		}
-		for(clb in panCallbacks) {
+		for(clb in refreshDopesheetKeys) {
 			clb(anim);
 		}
 	}
@@ -288,7 +299,6 @@ class FXScene extends FileView {
 		var scrollPanel = root.find(".anim-scroll");
 		scrollPanel.empty();
 		curveEdits = [];
-		panCallbacks = [];
 
 		for(elt in selection) {
 			var objPanel = new Element('<div>
@@ -353,24 +363,42 @@ class FXScene extends FileView {
 					updateExpanded();
 				});
 				var dopesheet = trackEl.find(".dopesheet");
-				for(key in curve.keys) {
-					var keyEl = new Element('<span class="key">').appendTo(dopesheet);
-					inline function update() keyEl.css({left: xt(key.time)});
-					update();
-					keyEl.mousedown(function(e) {
-						var offset = dopesheet.offset();
-						startDrag(function(e) {
-							var x = ixt(e.clientX - offset.left);
-							key.time = x;
-							curveEdit.refreshGraph(true, key);
+				function refreshDopesheet() {
+					refreshDopesheetKeys = [];
+					dopesheet.empty();
+					for(key in curve.keys) {
+						var keyEl = new Element('<span class="key">').appendTo(dopesheet);
+						inline function update() keyEl.css({left: xt(key.time)});
+						update();
+						keyEl.mousedown(function(e) {
+							var offset = dopesheet.offset();
+							var prevVal = key.time;
+							startDrag(function(e) {
+								var x = ixt(e.clientX - offset.left);
+								key.time = x;
+								curveEdit.refreshGraph(true, key);
+								update();
+							}, function(e) {
+								curveEdit.refreshGraph();
+								var newVal = key.time;
+								undo.change(Custom(function(undo) {
+									if(undo)
+										key.time = prevVal;
+									else
+										key.time = newVal;
+									update();
+									curveEdit.refreshGraph();
+								}));
+							});
+						});
+						refreshDopesheetKeys.push(function(anim) {
 							update();
-						}, function(e) {
-							curveEdit.refreshGraph();
 						});
-					});
-					panCallbacks.push(function(anim) {
-						update();
-					});
+					}
+				}
+				refreshDopesheet();
+				curveEdit.onChange = function(anim) {
+					refreshDopesheet();
 				}
 				updateExpanded();
 			}