CanvasSectionContainer: Fixes.

Bugs related to ordering of sections are fixed.
addSection and createSection functions are separated.
contextMenu event is added.
Sections' drawing orders are updated for future uses.

Signed-off-by: Gökay Şatır <gokaysatir@collabora.com>
Change-Id: I89127c97ad7b7dac4b293c4108c44cb6c4427134
This commit is contained in:
Gökay Şatır 2021-01-17 18:31:17 +03:00 committed by Gökay ŞATIR
parent 95a8028f00
commit 15bf787771
2 changed files with 98 additions and 70 deletions

View file

@ -102,6 +102,7 @@ class CanvasSectionObject {
onMouseLeave: Function; // Parameters: Point [x, y], e (native event object)
onClick: Function; // Parameters: Point [x, y], e (native event object)
onDoubleClick: Function; // Parameters: Point [x, y], e (native event object)
onContextMenu: Function;
onMouseWheel: Function; // Parameters: Point [x, y], DeltaY, e (native event object)
onLongPress: Function; // Parameters: Point [x, y], e (native event object)
onMultiTouchStart: Function; // Parameters: e (native event object)
@ -130,6 +131,7 @@ class CanvasSectionObject {
this.onMouseLeave = options.onMouseLeave ? options.onMouseLeave: function() {};
this.onClick = options.onClick ? options.onClick: function() {};
this.onDoubleClick = options.onDoubleClick ? options.onDoubleClick: function() {};
this.onContextMenu = options.onContextMenu ? options.onContextMenu: function() {};
this.onMouseWheel = options.onMouseWheel ? options.onMouseWheel: function() {};
this.onLongPress = options.onLongPress ? options.onLongPress: function() {};
this.onMultiTouchStart = options.onMultiTouchStart ? options.onMultiTouchStart: function() {};
@ -179,6 +181,7 @@ class CanvasSectionContainer {
this.canvas.onmouseup = this.onMouseUp.bind(this);
this.canvas.onclick = this.onClick.bind(this);
this.canvas.ondblclick = this.onDoubleClick.bind(this);
this.canvas.oncontextmenu = this.onContextMenu.bind(this);
this.canvas.onwheel = this.onMouseWheel.bind(this);
this.canvas.onmouseleave = this.onMouseLeave.bind(this);
this.canvas.ontouchstart = this.onTouchStart.bind(this);
@ -343,12 +346,11 @@ class CanvasSectionContainer {
if (section) {
section.onLongPress(this.convertPositionToSectionLocale(section, this.mousePosition), e);
}
this.potentialLongPress = false;
}
}
private onMouseDown (e: MouseEvent) { // Ignore this event, just rely on this.draggingSomething variable.
if (!this.touchEventInProgress) {
if (e.button === 0 && !this.touchEventInProgress) { // So, we only handle left button.
this.clearMousePositions();
this.positionOnMouseDown = this.convertPositionToCanvasLocale(e);
@ -361,7 +363,7 @@ class CanvasSectionContainer {
}
private onMouseUp (e: MouseEvent) { // Should be ignored unless this.draggingSomething = true.
if (!this.touchEventInProgress) {
if (e.button === 0 && !this.touchEventInProgress) {
this.positionOnMouseUp = this.convertPositionToCanvasLocale(e);
if (!this.draggingSomething) {
@ -379,6 +381,22 @@ class CanvasSectionContainer {
}
}
private onContextMenu (e: MouseEvent) {
var mousePosition = this.convertPositionToCanvasLocale(e);
var section: CanvasSectionObject = this.findSectionContainingPoint(mousePosition);
if (section) {
section.onContextMenu();
}
if (this.potentialLongPress) {
// LongPress triggers context menu.
// We should stop propagating here because we are using different context menu handlers for touch and mouse events.
// By stopping this event here, we can have real context menus (for mice) and other handlers (for longpress) at the same time (see Control.RowHeader.js).
e.preventDefault();
e.stopPropagation();
return false;
}
}
private onMouseWheel (e: WheelEvent) {
var point = this.convertPositionToCanvasLocale(e);
var delta = e.deltaY;
@ -478,6 +496,14 @@ class CanvasSectionContainer {
}
onResize (newWidth: number, newHeight: number) {
var container: HTMLElement = <HTMLElement>this.canvas.parentNode;
var cRect: ClientRect = container.getBoundingClientRect();
if (!newWidth)
newWidth = cRect.right - cRect.left;
if (!newHeight)
newHeight = cRect.bottom - cRect.top;
this.dpiScale = window.devicePixelRatio;
newWidth = Math.floor(newWidth * this.dpiScale);
newHeight = Math.floor(newHeight * this.dpiScale);
@ -504,7 +530,7 @@ class CanvasSectionContainer {
findSectionContainingPoint (point: Array<number>): any {
for (var i: number = this.sections.length - 1; i > -1; i--) { // Search from top to bottom. Top section will be sent as target section.
if (this.sections[i].interactable && this.doesSectionIncludePoint(this.sections[i], point))
if (this.sections[i].isLocated && this.sections[i].interactable && this.doesSectionIncludePoint(this.sections[i], point))
return this.sections[i];
}
@ -545,10 +571,7 @@ class CanvasSectionContainer {
private hitLeft (section: CanvasSectionObject): number {
var maxX = -1;
for (var i: number = 0; i < this.sections.length; i++) {
if (!this.sections[i].isLocated)
continue;
if (this.sections[i].zIndex === section.zIndex && this.sections[i].name !== section.name) {
if (this.sections[i].isLocated && this.sections[i].zIndex === section.zIndex && this.sections[i].name !== section.name) {
var currentLeft = this.sections[i].myTopLeft[0] + this.sections[i].size[0];
if (currentLeft > maxX && currentLeft < section.myTopLeft[0]) {
if (this.doSectionsIntersectOnYAxis(this.sections[i], section)) {
@ -567,10 +590,7 @@ class CanvasSectionContainer {
private hitRight (section: CanvasSectionObject): number {
var minX = Infinity;
for (var i: number = 0; i < this.sections.length; i++) {
if (!this.sections[i].isLocated)
continue;
if (this.sections[i].zIndex === section.zIndex && this.sections[i].name !== section.name) {
if (this.sections[i].isLocated && this.sections[i].zIndex === section.zIndex && this.sections[i].name !== section.name) {
var currentRight = this.sections[i].myTopLeft[0];
if (currentRight < minX && currentRight > section.myTopLeft[0]) {
if (this.doSectionsIntersectOnYAxis(this.sections[i], section)) {
@ -590,10 +610,7 @@ class CanvasSectionContainer {
private hitTop (section: CanvasSectionObject): number {
var maxY = -1;
for (var i: number = 0; i < this.sections.length; i++) {
if (!this.sections[i].isLocated)
continue;
if (this.sections[i].zIndex === section.zIndex && this.sections[i].name !== section.name) {
if (this.sections[i].isLocated && this.sections[i].zIndex === section.zIndex && this.sections[i].name !== section.name) {
var currentTop = this.sections[i].myTopLeft[1] + this.sections[i].size[1];
if (currentTop > maxY && currentTop < section.myTopLeft[1]) {
if (this.doSectionsIntersectOnXAxis(this.sections[i], section)) {
@ -612,10 +629,7 @@ class CanvasSectionContainer {
private hitBottom (section: CanvasSectionObject): number {
var minY = Infinity;
for (var i: number = 0; i < this.sections.length; i++) {
if (!this.sections[i].isLocated)
continue;
if (this.sections[i].zIndex === section.zIndex && this.sections[i].name !== section.name) {
if (this.sections[i].isLocated && this.sections[i].zIndex === section.zIndex && this.sections[i].name !== section.name) {
var currentBottom = this.sections[i].myTopLeft[1];
if (currentBottom < minY && currentBottom > section.myTopLeft[1]) {
if (this.doSectionsIntersectOnXAxis(this.sections[i], section)) {
@ -644,13 +658,11 @@ class CanvasSectionContainer {
private locateSections () {
for (var i: number = 0; i < this.sections.length; i++) {
var section: CanvasSectionObject = this.sections[i];
if (section.isLocated)
continue;
section.isLocated = false;
section.myTopLeft = null;
var x = section.anchor[1] === 'left' ? section.position[0]: (this.right - (section.position[0] + section.size[0]));
var y = section.anchor[0] === 'top' ? section.position[1]: (this.bottom - (section.position[1] + section.size[1]));
if (!section.boundToSection)
if (!section.boundToSection) {
section.myTopLeft = [x, y];
if (section.expand[0] !== '') {
if (section.expand.includes('left') || section.expand.includes('right'))
@ -658,6 +670,10 @@ class CanvasSectionContainer {
if (section.expand.includes('top') || section.expand.includes('bottom'))
section.size[1] = 0;
}
else {
section.isLocated = true;
}
}
else {
section.myTopLeft = [0, 0];
section.size = [0, 0];
@ -667,10 +683,7 @@ class CanvasSectionContainer {
// We have initial positions, now we'll expand them.
for (var i: number = 0; i < this.sections.length; i++) {
var section: CanvasSectionObject = this.sections[i];
if (section.isLocated)
continue;
if (section.expand && !section.boundToSection) {
if (section.expand[0] !== '' && !section.boundToSection) {
if (section.expand.includes('left')) {
var initialX = section.myTopLeft[0];
section.myTopLeft[0] = this.hitLeft(section);
@ -693,16 +706,11 @@ class CanvasSectionContainer {
section.isLocated = true;
}
else if (!section.boundToSection)
section.isLocated = true; // expand is empty => its location/size is already defined.
}
// Set location and size of bound sections.
for (var i: number = 0; i < this.sections.length; i++) {
var section: CanvasSectionObject = this.sections[i];
if (section.isLocated)
continue;
if (section.boundToSection) {
var parentSection = this.getSectionWithName(section.boundToSection);
if (parentSection) {
@ -710,9 +718,8 @@ class CanvasSectionContainer {
section.size[1] = parentSection.size[1];
section.myTopLeft[0] = parentSection.myTopLeft[0];
section.myTopLeft[1] = parentSection.myTopLeft[1];
section.isLocated = true;
}
section.isLocated = true; // FIXME: do only if parentSection is available ?
}
}
}
@ -732,13 +739,12 @@ class CanvasSectionContainer {
// According to processing order. Section with the highest processing order will be calculated last.
for (var i: number = 0; i < this.sections.length - 1; i++) {
var zIndex = this.sections[i].zIndex;
while (i < this.sections.length - 1 && zIndex === this.sections[i + 1].zIndex) {
if (this.sections[i].processingOrder > this.sections[i + 1].processingOrder) {
var temp = this.sections[i + 1];
this.sections[i + 1] = this.sections[i];
for (var j: number = i + 1; j < this.sections.length && this.sections[j].zIndex === zIndex; j++) {
if (this.sections[i].processingOrder > this.sections[j].processingOrder) {
var temp = this.sections[j];
this.sections[j] = this.sections[i];
this.sections[i] = temp;
}
i++;
}
}
}
@ -747,13 +753,12 @@ class CanvasSectionContainer {
// According to drawing order. Section with the highest drawing order will be drawn on top.
for (var i: number = 0; i < this.sections.length - 1; i++) {
var zIndex = this.sections[i].zIndex;
while (i < this.sections.length - 1 && zIndex === this.sections[i + 1].zIndex) {
if (this.sections[i].drawingOrder > this.sections[i + 1].drawingOrder) {
var temp = this.sections[i + 1];
this.sections[i + 1] = this.sections[i];
for (var j: number = i + 1; j < this.sections.length && this.sections[j].zIndex === zIndex; j++) {
if (this.sections[i].drawingOrder > this.sections[j].drawingOrder) {
var temp = this.sections[j];
this.sections[j] = this.sections[i];
this.sections[i] = temp;
}
i++;
}
}
}
@ -789,16 +794,24 @@ class CanvasSectionContainer {
}
}
setPenPosition (section: CanvasSectionObject) {
this.context.setTransform(1, 0, 0, 1, 0, 0);
this.context.translate(section.myTopLeft[0], section.myTopLeft[1]);
}
private drawSections () {
this.context.setTransform(1, 0, 0, 1, 0, 0);
this.context.fillStyle = this.clearColor;
this.context.clearRect(0, 0, this.canvas.width, this.canvas.height);
this.context.fillRect(0, 0, this.canvas.width, this.canvas.height);
this.context.font = String(20 * this.dpiScale) + "px Verdana";
for (var i: number = 0; i < this.sections.length; i++) {
this.context.translate(this.sections[i].myTopLeft[0], this.sections[i].myTopLeft[1]);
this.sections[i].onDraw();
this.context.translate(-this.sections[i].myTopLeft[0], -this.sections[i].myTopLeft[1]);
if (this.sections[i].isLocated) {
this.context.translate(this.sections[i].myTopLeft[0], this.sections[i].myTopLeft[1]);
this.sections[i].onDraw();
this.context.translate(-this.sections[i].myTopLeft[0], -this.sections[i].myTopLeft[1]);
}
}
//this.drawSectionBorders();
}
@ -846,23 +859,12 @@ class CanvasSectionContainer {
return true;
}
addSection (options: any, parentSectionName: string = null) {
createSection (options: any, parentSectionName: string = null) {
if (this.newSectionChecks(options)) {
// Every section can draw from Point(0, 0), their drawings will be translated to myTopLeft position.
var newSection: CanvasSectionObject = new CanvasSectionObject(options);
newSection.context = this.context;
newSection.documentTopLeft = this.documentTopLeft;
newSection.containerObject = this;
newSection.dpiScale = this.dpiScale;
newSection.sectionProperties.section = newSection;
newSection.boundToSection = parentSectionName;
this.sections.push(newSection);
newSection.onInitialize();
this.reNewAllSections(false);
this.drawSections();
this.pushSection(newSection);
return true;
}
else {
@ -870,6 +872,29 @@ class CanvasSectionContainer {
}
}
addSection (newSection: CanvasSectionObject) {
if (this.newSectionChecks(newSection)) {
this.pushSection(newSection);
return true;
}
else {
return false;
}
}
private pushSection (newSection: CanvasSectionObject) {
// Every section can draw from Point(0, 0), their drawings will be translated to myTopLeft position.
newSection.context = this.context;
newSection.documentTopLeft = this.documentTopLeft;
newSection.containerObject = this;
newSection.dpiScale = this.dpiScale;
newSection.sectionProperties.section = newSection;
this.sections.push(newSection);
newSection.onInitialize();
this.reNewAllSections(false);
this.drawSections();
}
removeSection (name: string) {
var found: boolean = false;
for (var i: number = 0; i < this.sections.length; i++) {

View file

@ -202,6 +202,8 @@ L.TileSectionManager = L.Class.extend({
if (!ctx)
ctx = this._paintContext();
this._sectionContainer.setPenPosition(this._tilesSection);
if (ctx.paneBoundsActive === true)
this._paintWithPanes(tile, ctx);
else
@ -210,16 +212,16 @@ L.TileSectionManager = L.Class.extend({
_addTilesSection: function () {
var that = this;
this._sectionContainer.addSection({
this._sectionContainer.createSection({
name: 'tiles',
anchor: 'top left',
position: [250 * that._dpiScale, 250 * that._dpiScale], // Set its initial position to somewhere blank. Other sections shouldn't cover this point after initializing.
size: [0, 0], // Going to be expanded, no initial width or height is necessary.
expand: 'top left bottom right', // Expand to all directions.
processingOrder: 1,
processingOrder: 5,
drawingOrder: 5,
zIndex: 5,
interactable: true,
interactable: false,
sectionProperties: {
docLayer: that._layer,
tsManager: that
@ -233,13 +235,13 @@ L.TileSectionManager = L.Class.extend({
_addGridSection: function () {
var that = this;
this._sectionContainer.addSection({
this._sectionContainer.createSection({
name: 'calc grid',
anchor: 'top left',
position: [0, 0],
size: [0, 0],
expand: '',
processingOrder: 2, // Size and position will be copied, this value is not important.
processingOrder: 5, // Size and position will be copied, this value is not important.
drawingOrder: 4,
zIndex: 5,
// Even if this one is drawn on top, won't be able to catch events.
@ -302,13 +304,13 @@ L.TileSectionManager = L.Class.extend({
// This section is added when debug is enabled. Splits are enabled for only Calc for now.
_addSplitsSection: function () {
var that = this;
this._sectionContainer.addSection({
this._sectionContainer.createSection({
name: 'splits',
anchor: 'top left',
position: [0, 0],
size: [0, 0],
expand: '',
processingOrder: 3, // Size and position will be copied, this value is not important.
processingOrder: 5, // Size and position will be copied, this value is not important.
drawingOrder: 8, // Above tiles section (same zIndex, higher drawing order).
zIndex: 5,
// Even if this one is drawn on top, won't be able to catch events.
@ -324,13 +326,13 @@ L.TileSectionManager = L.Class.extend({
// This section is added when debug is enabled.
_addTilePixelGridSection: function () {
var that = this;
this._sectionContainer.addSection({
this._sectionContainer.createSection({
name: 'tile pixel grid',
anchor: 'top left',
position: [0, 0],
size: [0, 0],
expand: '',
processingOrder: 4, // Size and position will be copied, this value is not important.
processingOrder: 5, // Size and position will be copied, this value is not important.
drawingOrder: 6,
zIndex: 5,
interactable: false,
@ -572,6 +574,7 @@ L.CanvasTileLayer = L.TileLayer.extend({
if (this._docType === 'spreadsheet') {
this._painter._addGridSection();
}
this._syncTileContainerSize();
},
_syncTilePanePos: function () {