Add undo for created Entities in order to be able to remove entities

when drawing in desktop mode.
Fix keyboard not showing.
Fix app button not being deactivated when switching to another app.
This commit is contained in:
Artur Gomes 2017-07-26 17:53:13 +01:00
parent c94774ec18
commit 91a6f2c8d9
5 changed files with 121 additions and 60 deletions

View file

@ -12,7 +12,7 @@
button,
BUTTON_NAME = "PAINT",
//undo vars
UNDO_STACK_SIZE = 5,
UNDO_STACK_SIZE = 10,
undoStack = [];
isFingerPainting = false,
isTabletFocused = false,
@ -119,10 +119,25 @@
texture = textureURL;
}
function undoErasing() {
function undo() {
var undo = undoStack.pop();
if (undo) {
Entities.addEntity(undo);
if (undoStack.length == 0) {
var undoDisableEvent = {type: "undoDisable", value: true};
tablet.emitScriptEvent(JSON.stringify(undoDisableEvent));
}
if (undo.type == "deleted") {
var prevEntityId = undo.data.id;
var newEntity = Entities.addEntity(undo.data);
//restoring a deleted entity will create a new entity with a new id therefore we need to update
//the created elements id in the undo stack. For the delete elements though, it is not necessary
//to update the id since you can't delete the same entity twice
for (var i = 0; i < undoStack.length; i++) {
if (undoStack[i].type == "created" && undoStack[i].data == prevEntityId) {
undoStack[i].data = newEntity;
}
}
} else {
Entities.deleteEntity(undo.data);
}
}
@ -235,6 +250,7 @@
}
isDrawingLine = false;
addElementToUndoStack({type: "created", data: entityID});
//print("After adding script 3: " + JSON.stringify(Entities.getEntityProperties(entityID)));
}
@ -280,7 +296,7 @@
// Delete found entity.
if (found) {
addElementToUndoStack(Entities.getEntityProperties(foundID));
addElementToUndoStack({type: "deleted", data: Entities.getEntityProperties(foundID)});
Entities.deleteEntity(foundID);
/*Entities.editEntity(entityID, {
color: «,
@ -305,7 +321,7 @@
changeStrokeWidthMultiplier: changeStrokeWidthMultiplier,
changeTexture: changeTexture,
isDrawing: isDrawing,
undoErasing: undoErasing,
undo: undo,
getStrokeColor: getStrokeColor,
getStrokeWidth: getStrokeWidth,
getEntityID: getEntityID,
@ -796,8 +812,8 @@
return;
}
if (message[0] === "undo"){
leftBrush.undoErasing();
rightBrush.undoErasing();
leftBrush.undo();
rightBrush.undo();
return;
}
if (message[0] === "hand"){
@ -853,6 +869,7 @@
savedSettings.customColors = Settings.getValue("customColors", []);
savedSettings.currentTab = Settings.getValue("currentTab", 0);
savedSettings.currentTriggerWidthEnabled = Settings.getValue("currentTriggerWidthEnabled", true);
savedSettings.undoDisable = undoStack.length == 0;
isLeftHandDominant = savedSettings.currentDrawingHand;
}
@ -893,18 +910,26 @@
}
function onTabletScreenChanged(type, url) {
//var TABLET_SCREEN_CLOSED = "Closed";
//var TABLET_SCREEN_HOME = "Home";
//isTabletDisplayed = type !== TABLET_SCREEN_CLOSED;
//if (type === TABLET_SCREEN_HOME) {
// if (isFingerPainting) {
// isFingerPainting = false;
// disableProcessing();
// }
// button.editProperties({ isActive: isFingerPainting });
// print("Closing the APP");
//}
//updateHandFunctions();
var TABLET_SCREEN_CLOSED = "Closed";
var TABLET_SCREEN_HOME = "Home";
isTabletDisplayed = type !== TABLET_SCREEN_CLOSED;
if (type === TABLET_SCREEN_HOME) {
if (isFingerPainting) {
isFingerPainting = false;
disableProcessing();
}
button.editProperties({ isActive: isFingerPainting });
print("Closing the APP");
isFingerPainting = type === "Web" && url.indexOf("fingerPaint/html/main.html") > -1;
if (!isFingerPainting) {
disableProcessing();
}
button.editProperties({ isActive: isFingerPainting });
updateHandFunctions();
}
@ -919,9 +944,11 @@
case "appReady":
isTabletFocused = false; //make sure we can set the focus on the tablet again
break;
case "changeTab":
Settings.setValue("currentTab", event.currentTab);
break;
case "changeColor":
if (!isBrushColored) {
print("HMD ACTIVE: " + HMD.active);
@ -934,12 +961,14 @@
});
}
break;
case "switchTriggerPressureWidth":
//print("changing pressure sensitive width...");
Settings.setValue("currentTriggerWidthEnabled", event.enabled);
leftBrush.setTriggerPressureWidthEnabled(event.enabled);
rightBrush.setTriggerPressureWidthEnabled(event.enabled);
break;
case "addCustomColor":
//print("Adding custom color");
var customColors = Settings.getValue("customColors", []);
@ -994,9 +1023,9 @@
//print("Going to undo");
//The undo is called only on the right brush because the undo stack is global, meaning that
//calling undoErasing on both the left and right brush would cause the stack to pop twice.
//calling undo on both the left and right brush would cause the stack to pop twice.
//Using the leftBrush instead of the rightBrush would have the exact same effect.
rightBrush.undoErasing();
rightBrush.undo();
break;
case "changeBrushHand":
@ -1042,6 +1071,9 @@
function addElementToUndoStack(item)
{
var undoDisableEvent = {type: "undoDisable", value: false};
tablet.emitScriptEvent(JSON.stringify(undoDisableEvent));
if (undoStack.length + 1 > UNDO_STACK_SIZE) {
undoStack.splice(0, 1);
}
@ -1098,30 +1130,23 @@
print(JSON.stringify(event));
if (event.isLeftButton) {
rightBrush.startLine(getFingerPosition(event.x, event.y), 0.03);
} else if (event.isMiddleButton) {
//delete first line in sight
//var pickRay = getFingerPosition(event.x, event.y);
// entities = Entities.findEntities(MyAvatar.position, 10);
// Fine polyline entity with closest point within search radius.
/*for (i = 0, entitiesLength = entities.length; i < entitiesLength; i += 1) {
print("NEAR ENTITIES: " + JSON.stringify(Entities.getEntityProperties(entities[i])));
}*/
var pickRay = Camera.computePickRay(event.x, event.y);
var entityToDelete = Entities.findRayIntersection(pickRay, false, [Entities.findEntities(MyAvatar.position, 1000)], []);
print("Entity to DELETE: " + JSON.stringify(entityToDelete));
var line3d = Overlays.addOverlay("line3d", {
start: pickRay.origin,
end: Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, 100)),
color: { red: 255, green: 0, blue: 255},
lineWidth: 5
});
if (entityToDelete.intersects) {
print("Entity to DELETE Properties: " + JSON.stringify(Entities.getEntityProperties(entityToDelete.entityID)));
//Entities.deleteEntity(entityToDelete.entityID);
}
}
}
//won't work until findRayIntersection works with polylines
//else if (event.isMiddleButton) {
// var pickRay = Camera.computePickRay(event.x, event.y);
// var entityToDelete = Entities.findRayIntersection(pickRay, false, [Entities.findEntities(MyAvatar.position, 1000)], []);
// print("Entity to DELETE: " + JSON.stringify(entityToDelete));
// var line3d = Overlays.addOverlay("line3d", {
// start: pickRay.origin,
// end: Vec3.sum(pickRay.origin, Vec3.multiply(pickRay.direction, 100)),
// color: { red: 255, green: 0, blue: 255},
// lineWidth: 5
// });
// if (entityToDelete.intersects) {
// print("Entity to DELETE Properties: " + JSON.stringify(Entities.getEntityProperties(entityToDelete.entityID)));
// //Entities.deleteEntity(entityToDelete.entityID);
// }
//}
}
function mouseFinishLine(event){

View file

@ -3,16 +3,26 @@
<style type="text/css">
.changeHandButton {
width: 200px;
height: 200px;
width: 216px;
height: 216px;
color: white;
background-color: #2e2e2e;
border: none;
float: left;
margin: 2px;
text-transform: uppercase;
font-family: Raleway-Bold;
font-size: 13px;
}
.brushButton {
max-width: 220px,
padding: 10px,
background-color: #666666
.changeHandButton:first-child {
margin-left: 0px;
}
.changeHandButton:last-child {
margin-right: 0px;
}
.selectedHand {
background-color: #f4e842
background-color: rgb(16, 128, 184);
}
</style>

View file

@ -1,6 +1,6 @@
<!--Note: change the parent postmessage second parameter due to possible security issues-->
<link rel="stylesheet" type="text/css" href="../../html/css/colpick.css">
<link rel="stylesheet" type="text/css" href="../../html/css/edit-style.css">
<link rel="stylesheet" type="text/css" href="../../html/css/colpick.css">
<script type="text/javascript" src="../../html/js/eventBridgeLoader.js"></script>
<script type="text/javascript" src="../../html/js/keyboardControl.js"></script>
<script src="../../html/js/jquery-2.1.4.min.js"></script>
@ -94,7 +94,7 @@
<script>
$('#colorpicker').colpick({
flat:true,
layout:'hex',
layout:'full',
colorScheme:'dark',
submitText: 'Add custom color',
onChange: function(hsb, hex, rgb, el) {
@ -108,6 +108,8 @@
var COLUMNS = 18, ROWS = 10;
var lastSelectedButton = null;
var currentSelectedColorOrigin = "custom"; //where the color was picked from
var EventBridge = parent.EventBridge;
function addColors() {
//10-90%
var startingColors = [];
@ -292,9 +294,8 @@
var color = document.getElementById(currentSelectedColorOrigin + "(" + colorArray[0] + "," + colorArray[1] + "," + colorArray[2] + ")");
selectButton(color);
}
$(window).load(function(){
var EventBridge = parent.EventBridge;
setUpKeyboardControl();
});
</script>

View file

@ -2,13 +2,16 @@
<link rel="stylesheet" type="text/css" href="../../html/css/edit-style.css">
<style type="text/css">
#undoButton {
width: 200px;
#undo {
width: 438px;
height: 200px;
margin: auto;
}
</style>
<!--<button id="undoButton" onclick="undo()">Undo</button>-->
<input type="button" value="undo" disabled id="undo" onclick="undo()"></input>
<button id="undoButton" onclick="undo()">Undo</button>
<script type="text/javascript">
function undo() {
var undoEvent = {
@ -16,4 +19,20 @@
};
parent.postMessage(JSON.stringify(undoEvent), "*");
}
window.addEventListener("message", setUndoState, false);
function setUndoState(message) {
//document.getElementById("message").innerHTML = "message received!";
var event = JSON.parse(message.data);
if (!event.value) {
document.getElementById("undo").removeAttribute("disabled");
} else {
document.getElementById("undo").setAttribute("disabled", event.value);
}
}
restoreUndoState(JSON.parse(decodeURIComponent(window.parent.location.search).substring(1)));
function restoreUndoState(undoState) {
setUndoState({data: JSON.stringify({value: undoState.undoDisable})});
}
</script>

View file

@ -38,7 +38,7 @@
<div id="tabs">
<span class="tabButton" onclick="selectTab(0)"><img class="tabIcon" src="../content/tabicons/colorpaletteBtn.png"/>Palette</span>
<span class="tabButton" onclick="selectTab(1)"><img class="tabIcon" src="../content/tabicons/brushesBtn.png"/>Brushes</span>
<span class="tabButton" onclick="selectTab(2)"><img class="tabIcon" src="../content/tabicons/eraser.png"/>Eraser</span>
<span class="tabButton" onclick="selectTab(2)"><img class="tabIcon" src="../content/tabicons/eraser.png"/>Undo</span>
<span class="tabButton" onclick="selectTab(3)"><img class="tabIcon" src="../content/tabicons/pointingfinger128px.png"/>Hand</span>
</div>
<div id="settingsLoading" style="display: none; background-color: #F44336; color: white; padding: 8px">Loading previous settings</div>
@ -53,7 +53,6 @@
<script type="text/javascript">
var currentTab = 0;
var settings;
var iframesLoaded = 0;
function selectTab(tabIndex) {
var tabs = document.getElementById("tabs").children;
@ -80,12 +79,19 @@
}
}
//Accept events from iframes
EventBridge.scriptEventReceived.connect(function (message) {
var event = JSON.parse(message);
if (event.type == "undoDisable") {
document.getElementById("eraserTab").contentWindow.postMessage(message, "*");
}
});
//Accept events function() from iframes
//https://stackoverflow.com/questions/8822907/html5-cross-browser-iframe-postmessage-child-to-parent
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
//restore last opened tab
selectTab(JSON.parse(decodeURIComponent(window.location.search).substring(1)).currentTab);
// Listen to message from child window