Commit c0374682 authored by Evan W. Patton's avatar Evan W. Patton Committed by Jeffrey Schiller

Add WorkspaceMove event for undoing viewport moves

We added a mechanism that moves the workspace when highlighting a
procedure definition block. However, we do not provide a mechanism to
go back to the original viewport position prior to the move. This
commit adds a WorkspaceMove event that is recorded when the workspace
is shifted and can be undo via the normal undo/redo stack to return
the user from where they came in the workspace.

Note this is not robust to changes in the viewport size between
operations.

Change-Id: I09f1af2f3d7db62af0f1487a90a56a66f99273bc
parent 7f5bcb65
...@@ -845,6 +845,7 @@ Blockly.Blocks['procedures_callnoreturn'] = { ...@@ -845,6 +845,7 @@ Blockly.Blocks['procedures_callnoreturn'] = {
var def = Blockly.Procedures.getDefinition(name, workspace); var def = Blockly.Procedures.getDefinition(name, workspace);
if (def) { if (def) {
def.select(); def.select();
var event = new AI.Events.WorkspaceMove(workspace.id);
// Attempt to center the definition block, but preserve a minimum X, Y position so that // Attempt to center the definition block, but preserve a minimum X, Y position so that
// the definition of the block always appears on screen for visually large procedures // the definition of the block always appears on screen for visually large procedures
...@@ -856,6 +857,9 @@ Blockly.Blocks['procedures_callnoreturn'] = { ...@@ -856,6 +857,9 @@ Blockly.Blocks['procedures_callnoreturn'] = {
var midX = minLeft + (wh.width - metrics.viewWidth) / 2; var midX = minLeft + (wh.width - metrics.viewWidth) / 2;
var midY = minTop + (wh.height - metrics.viewHeight) / 2; var midY = minTop + (wh.height - metrics.viewHeight) / 2;
def.workspace.scrollbar.set(Math.min(minLeft, midX), Math.min(minTop, midY)); def.workspace.scrollbar.set(Math.min(minLeft, midX), Math.min(minTop, midY));
event.recordNew();
Blockly.Events.fire(event);
workspace.getParentSvg().parentElement.focus();
} }
}; };
options.push(option); options.push(option);
......
...@@ -70,6 +70,12 @@ AI.Events.BLOCKS_ARRANGE_START = 'blocks.arrange.start'; ...@@ -70,6 +70,12 @@ AI.Events.BLOCKS_ARRANGE_START = 'blocks.arrange.start';
*/ */
AI.Events.BLOCKS_ARRANGE_END = 'blocks.arrange.end'; AI.Events.BLOCKS_ARRANGE_END = 'blocks.arrange.end';
/**
* Type identifier used for programmatic workspace shifts.
* @type {string}
*/
AI.Events.WORKSPACE_VIEWPORT_MOVE = "blocks.workspace.move";
/** /**
* Abstract class for all App Inventor events. * Abstract class for all App Inventor events.
* @constructor * @constructor
...@@ -391,6 +397,89 @@ AI.Events.EndArrangeBlocks.prototype.run = function(forward) { ...@@ -391,6 +397,89 @@ AI.Events.EndArrangeBlocks.prototype.run = function(forward) {
} }
}; };
/**
* Class for capturing when the workspace is moved programmatically, to allow undoing by the user.
* @param {string} workspaceId The workspace that is being moved.
* @constructor
*/
AI.Events.WorkspaceMove = function(workspaceId) {
AI.Events.WorkspaceMove.superClass_.constructor.call(this);
this.workspaceId = workspaceId;
var metrics = Blockly.Workspace.getById(workspaceId).getMetrics();
this.oldX = metrics.viewLeft - metrics.contentLeft;
this.oldY = metrics.viewTop - metrics.contentTop;
this.newX = null;
this.newY = null;
};
goog.inherits(AI.Events.WorkspaceMove, AI.Events.Abstract);
/**
* Type of this event.
* @type {string}
*/
AI.Events.WorkspaceMove.prototype.type = AI.Events.WORKSPACE_VIEWPORT_MOVE;
/**
* Is the event transient?
* @type {boolean}
*/
AI.Events.WorkspaceMove.prototype.isTransient = true;
/**
* Encode the event as JSON.
* @returns {!Object}
*/
AI.Events.WorkspaceMove.prototype.toJson = function() {
var json = AI.Events.WorkspaceMove.superClass_.toJson.call(this);
json['workspaceId'] = this.workspaceId;
if (this.newX) {
json['newX'] = this.newX;
}
if (this.newY) {
json['newY'] = this.newY;
}
return json;
};
/**
* Decode the JSON event.
* @param {!Object} json JSON representation.
*/
AI.Events.WorkspaceMove.prototype.fromJson = function() {
AI.Events.WorkspaceMove.superClass_.fromJson.call(this, json);
this.workspaceId = json['workspaceId'];
this.newX = json['newX'];
this.newY = json['newY'];
};
/**
* Record the new state of the workspace after the operation has occurred.
*/
AI.Events.WorkspaceMove.prototype.recordNew = function() {
var metrics = Blockly.Workspace.getById(this.workspaceId).getMetrics();
this.newX = metrics.viewLeft - metrics.contentLeft;
this.newY = metrics.viewTop - metrics.contentTop;
};
/**
* Check whether the event is null. For workspace moves, this is true if and only if that the new
* and old coordinates are the same.
* @returns {boolean}
*/
AI.Events.WorkspaceMove.prototype.isNull = function() {
return this.oldX === this.newX && this.oldY === this.newY;
};
/**
* Run a workspace move event.
* @param {boolean} forward True if run forward, false if run backward (undo).
*/
AI.Events.WorkspaceMove.prototype.run = function(forward) {
var workspace = Blockly.Workspace.getById(this.workspaceId);
var x = forward ? this.newX : this.oldX;
var y = forward ? this.newY : this.oldY;
workspace.scrollbar.set(x, y);
};
/** /**
* Filter the queued events and merge duplicates. This version is O(n) versus the implementation * Filter the queued events and merge duplicates. This version is O(n) versus the implementation
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment