kopia lustrzana https://github.com/backface/turtlestitch
Morphic enhancements
* enable exporting a screenshot of the World * enable more fine-grained control over dragging position correction * enable all Morphs to “scrollIntoView()” * keyboard accessibility for menuspull/3/merge
rodzic
6bb7f662e2
commit
f829635106
205
morphic.js
205
morphic.js
|
@ -2501,6 +2501,32 @@ Morph.prototype.keepWithin = function (aMorph) {
|
|||
}
|
||||
};
|
||||
|
||||
Morph.prototype.scrollIntoView = function () {
|
||||
var leftOff, rightOff, topOff, bottomOff,
|
||||
sf = this.parentThatIsA(ScrollFrameMorph);
|
||||
if (!sf) {return; }
|
||||
rightOff = Math.min(
|
||||
this.fullBounds().right() - sf.right(),
|
||||
sf.contents.right() - sf.right()
|
||||
);
|
||||
if (rightOff > 0) {
|
||||
sf.contents.moveBy(new Point(-rightOff, 0));
|
||||
}
|
||||
leftOff = this.fullBounds().left() - sf.left();
|
||||
if (leftOff < 0) {
|
||||
sf.contents.moveBy(new Point(-leftOff, 0));
|
||||
}
|
||||
topOff = this.fullBounds().top() - sf.top();
|
||||
if (topOff < 0) {
|
||||
sf.contents.moveBy(new Point(0, -topOff));
|
||||
}
|
||||
bottomOff = this.fullBounds().bottom() - sf.bottom();
|
||||
if (bottomOff > 0) {
|
||||
sf.contents.moveBy(new Point(0, -bottomOff));
|
||||
}
|
||||
sf.adjustScrollBars();
|
||||
};
|
||||
|
||||
// Morph accessing - dimensional changes requiring a complete redraw
|
||||
|
||||
Morph.prototype.setExtent = function (aPoint) {
|
||||
|
@ -3092,6 +3118,13 @@ Morph.prototype.rootForGrab = function () {
|
|||
return this.parent.rootForGrab();
|
||||
};
|
||||
|
||||
Morph.prototype.isCorrectingOutsideDrag = function () {
|
||||
// make sure I don't "trail behind" the hand when dragged
|
||||
// override for morphs that you want to be dragged outside
|
||||
// their full bounds
|
||||
return true;
|
||||
};
|
||||
|
||||
Morph.prototype.wantsDropOf = function (aMorph) {
|
||||
// default is to answer the general flag - change for my heirs
|
||||
if ((aMorph instanceof HandleMorph) ||
|
||||
|
@ -3174,6 +3207,17 @@ Morph.prototype.move = function () {
|
|||
);
|
||||
};
|
||||
|
||||
Morph.prototype.moveCenter = function () {
|
||||
this.world().activeHandle = new HandleMorph(
|
||||
this,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
'moveCenter'
|
||||
);
|
||||
};
|
||||
|
||||
Morph.prototype.hint = function (msg) {
|
||||
var m, text;
|
||||
text = msg;
|
||||
|
@ -3722,7 +3766,7 @@ HandleMorph.prototype.init = function (
|
|||
this.target = target || null;
|
||||
this.minExtent = new Point(minX || 0, minY || 0);
|
||||
this.inset = new Point(insetX || 0, insetY || insetX || 0);
|
||||
this.type = type || 'resize'; // can also be 'move'
|
||||
this.type = type || 'resize'; // can also be 'move', 'moveCenter'
|
||||
HandleMorph.uber.init.call(this);
|
||||
this.color = new Color(255, 255, 255);
|
||||
this.isDraggable = false;
|
||||
|
@ -3747,11 +3791,15 @@ HandleMorph.prototype.drawNew = function () {
|
|||
);
|
||||
this.image = this.normalImage;
|
||||
if (this.target) {
|
||||
this.setPosition(
|
||||
this.target.bottomRight().subtract(
|
||||
this.extent().add(this.inset)
|
||||
)
|
||||
);
|
||||
if (this.type === 'moveCenter') {
|
||||
this.setCenter(this.target.center());
|
||||
} else { // 'resize', 'move'
|
||||
this.setPosition(
|
||||
this.target.bottomRight().subtract(
|
||||
this.extent().add(this.inset)
|
||||
)
|
||||
);
|
||||
}
|
||||
this.target.add(this);
|
||||
this.target.changed();
|
||||
}
|
||||
|
@ -3763,6 +3811,7 @@ HandleMorph.prototype.drawOnCanvas = function (
|
|||
shadowColor
|
||||
) {
|
||||
var context = aCanvas.getContext('2d'),
|
||||
isSquare = (this.type.indexOf('move') === 0),
|
||||
p1,
|
||||
p11,
|
||||
p2,
|
||||
|
@ -3774,7 +3823,7 @@ HandleMorph.prototype.drawOnCanvas = function (
|
|||
|
||||
context.strokeStyle = color.toString();
|
||||
|
||||
if (this.type === 'move') {
|
||||
if (isSquare) {
|
||||
|
||||
p1 = this.bottomLeft().subtract(this.position());
|
||||
p11 = p1.copy();
|
||||
|
@ -3811,7 +3860,7 @@ HandleMorph.prototype.drawOnCanvas = function (
|
|||
|
||||
context.strokeStyle = shadowColor.toString();
|
||||
|
||||
if (this.type === 'move') {
|
||||
if (isSquare) {
|
||||
|
||||
p1 = this.bottomLeft().subtract(this.position());
|
||||
p11 = p1.copy();
|
||||
|
@ -3853,12 +3902,17 @@ HandleMorph.prototype.step = null;
|
|||
|
||||
HandleMorph.prototype.mouseDownLeft = function (pos) {
|
||||
var world = this.root(),
|
||||
offset = pos.subtract(this.bounds.origin),
|
||||
offset,
|
||||
myself = this;
|
||||
|
||||
if (!this.target) {
|
||||
return null;
|
||||
}
|
||||
if (this.type === 'moveCenter') {
|
||||
offset = pos.subtract(this.center());
|
||||
} else {
|
||||
offset = pos.subtract(this.bounds.origin);
|
||||
}
|
||||
this.step = function () {
|
||||
var newPos, newExt;
|
||||
if (world.hand.mouseButton) {
|
||||
|
@ -3875,6 +3929,8 @@ HandleMorph.prototype.mouseDownLeft = function (pos) {
|
|||
myself.extent().add(myself.inset)
|
||||
)
|
||||
);
|
||||
} else if (this.type === 'moveCenter') {
|
||||
myself.target.setCenter(newPos);
|
||||
} else { // type === 'move'
|
||||
myself.target.setPosition(
|
||||
newPos.subtract(this.target.extent())
|
||||
|
@ -6652,6 +6708,8 @@ MenuMorph.prototype.init = function (target, title, environment, fontSize) {
|
|||
this.label = null;
|
||||
this.world = null;
|
||||
this.isListContents = false;
|
||||
this.hasFocus = false;
|
||||
this.selection = null;
|
||||
|
||||
// initialize inherited properties:
|
||||
MenuMorph.uber.init.call(this);
|
||||
|
@ -6871,6 +6929,7 @@ MenuMorph.prototype.popup = function (world, pos) {
|
|||
}
|
||||
world.add(this);
|
||||
world.activeMenu = this;
|
||||
this.world = world; // optionally enable keyboard support
|
||||
this.fullChanged();
|
||||
};
|
||||
|
||||
|
@ -6901,6 +6960,105 @@ MenuMorph.prototype.popUpCenteredInWorld = function (world) {
|
|||
);
|
||||
};
|
||||
|
||||
// MenuMorph keyboard accessibility
|
||||
|
||||
MenuMorph.prototype.getFocus = function () {
|
||||
this.world.keyboardReceiver = this;
|
||||
this.selection = null;
|
||||
this.selectFirst();
|
||||
this.hasFocus = true;
|
||||
};
|
||||
|
||||
MenuMorph.prototype.processKeyDown = function (event) {
|
||||
//console.log(event.keyCode);
|
||||
switch (event.keyCode) {
|
||||
case 13: // 'enter'
|
||||
case 32: // 'space'
|
||||
if (this.selection) {
|
||||
this.selection.mouseClickLeft();
|
||||
}
|
||||
return;
|
||||
case 27: // 'esc'
|
||||
return this.destroy();
|
||||
case 38: // 'up arrow'
|
||||
return this.selectUp();
|
||||
case 40: // 'down arrow'
|
||||
return this.selectDown();
|
||||
default:
|
||||
nop();
|
||||
}
|
||||
};
|
||||
|
||||
MenuMorph.prototype.processKeyUp = function (event) {
|
||||
nop(event);
|
||||
};
|
||||
|
||||
MenuMorph.prototype.processKeyPress = function (event) {
|
||||
nop(event);
|
||||
};
|
||||
|
||||
MenuMorph.prototype.selectFirst = function () {
|
||||
var i;
|
||||
for (i = 0; i < this.children.length; i += 1) {
|
||||
if (this.children[i] instanceof MenuItemMorph) {
|
||||
this.select(this.children[i]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MenuMorph.prototype.selectUp = function () {
|
||||
var triggers, idx;
|
||||
|
||||
triggers = this.children.filter(function (each) {
|
||||
return each instanceof MenuItemMorph;
|
||||
});
|
||||
if (!this.selection) {
|
||||
if (triggers.length) {
|
||||
this.select(triggers[0]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
idx = triggers.indexOf(this.selection) - 1;
|
||||
if (idx < 0) {
|
||||
idx = triggers.length - 1;
|
||||
}
|
||||
this.select(triggers[idx]);
|
||||
};
|
||||
|
||||
MenuMorph.prototype.selectDown = function () {
|
||||
var triggers, idx;
|
||||
|
||||
triggers = this.children.filter(function (each) {
|
||||
return each instanceof MenuItemMorph;
|
||||
});
|
||||
if (!this.selection) {
|
||||
if (triggers.length) {
|
||||
this.select(triggers[0]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
idx = triggers.indexOf(this.selection) + 1;
|
||||
if (idx >= triggers.length) {
|
||||
idx = 0;
|
||||
}
|
||||
this.select(triggers[idx]);
|
||||
};
|
||||
|
||||
MenuMorph.prototype.select = function (aMenuItem) {
|
||||
this.unselectAllItems();
|
||||
aMenuItem.image = aMenuItem.highlightImage;
|
||||
aMenuItem.changed();
|
||||
this.selection = aMenuItem;
|
||||
};
|
||||
|
||||
MenuMorph.prototype.destroy = function () {
|
||||
if (this.hasFocus) {
|
||||
this.world.keyboardReceiver = null;
|
||||
}
|
||||
MenuMorph.uber.destroy.call(this);
|
||||
};
|
||||
|
||||
// StringMorph /////////////////////////////////////////////////////////
|
||||
|
||||
// I am a single line of text
|
||||
|
@ -9586,32 +9744,16 @@ HandMorph.prototype.processMouseMove = function (event) {
|
|||
this.grabOrigin = this.morphToGrab.situation();
|
||||
}
|
||||
if (morph) {
|
||||
// if the mouse has left its fullBounds, center it
|
||||
// if the mouse has left its fullBounds, allow to center it
|
||||
fb = morph.fullBounds();
|
||||
if (!fb.containsPoint(pos)) {
|
||||
if (!fb.containsPoint(pos) &&
|
||||
morph.isCorrectingOutsideDrag()) {
|
||||
this.bounds.origin = fb.center();
|
||||
this.grab(morph);
|
||||
this.setPosition(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
original, more cautious code for grabbing Morphs,
|
||||
retained in case of needing to fall back:
|
||||
|
||||
if (morph === this.morphToGrab) {
|
||||
if (morph.isDraggable) {
|
||||
this.grab(morph);
|
||||
} else if (morph.isTemplate) {
|
||||
morph = morph.fullCopy();
|
||||
morph.isTemplate = false;
|
||||
morph.isDraggable = true;
|
||||
this.grab(morph);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
this.mouseOverList.forEach(function (old) {
|
||||
|
@ -10399,6 +10541,13 @@ WorldMorph.prototype.contextMenu = function () {
|
|||
'inspect',
|
||||
'open a window on\nall properties'
|
||||
);
|
||||
menu.addItem(
|
||||
"screenshot...",
|
||||
function () {
|
||||
window.open(this.fullImageClassic().toDataURL());
|
||||
},
|
||||
'open a new window\nwith a picture of this morph'
|
||||
);
|
||||
menu.addLine();
|
||||
menu.addItem(
|
||||
"restore display",
|
||||
|
|
Ładowanie…
Reference in New Issue