devexpress-richedit
Version:
DevExpress Rich Text Editor is an advanced word-processing tool designed for working with rich text documents.
92 lines (91 loc) • 4.88 kB
JavaScript
import { DocumentLayoutDetailsLevel } from "../../../common/layout/document-layout-details-level";
import { LayoutPoint } from "../../../common/layout/layout-point";
import { SetSelectionStateOptions } from "../../../common/selection/selection";
import { SelectionCommandBase } from "./selection-command-base";
import { ScrollTopInfo } from "../../../common/canvas/canvas-manager";
import { ScrollState } from "../../../common/scroll/model-states";
import { LayoutPositionMainSubDocumentCreator, LayoutPositionCreatorConflictFlags } from "../../../common/layout-engine/layout-position-creator";
import { FixedInterval } from "@devexpress/utils/lib/intervals/fixed";
export class GoToPageCommandBase extends SelectionCommandBase {
get scale() {
return this.control.viewManager.zoomLevel;
}
executeCore(_state, _options) {
const selection = this.selection;
const initPosition = selection.forwardDirection ? selection.lastSelectedInterval.end : selection.lastSelectedInterval.start;
const layoutPosition = new LayoutPositionMainSubDocumentCreator(this.control.layout, this.selection.activeSubDocument, initPosition, DocumentLayoutDetailsLevel.Box)
.create(new LayoutPositionCreatorConflictFlags().setDefault(false), new LayoutPositionCreatorConflictFlags().setDefault(true));
if (!layoutPosition)
return false;
const charOffset = initPosition - layoutPosition.getLogPosition(DocumentLayoutDetailsLevel.Box);
const x = layoutPosition.pageArea.x + layoutPosition.column.x + layoutPosition.row.x + layoutPosition.box.x + layoutPosition.box.getCharOffsetXInPixels(this.control.measurer, charOffset);
const y = layoutPosition.pageArea.y + layoutPosition.column.y + layoutPosition.row.y + layoutPosition.box.y;
this.goToPage(layoutPosition, x, y);
return true;
}
getPageOffsetY(pageIndex) {
const page = this.control.layout.pages[pageIndex];
return this.control.viewManager.sizes.getPageOffsetY(page);
}
findPageIndexByOffsetY(offsetY) {
return this.control.layout.findPageIndexByOffsetY(offsetY, this.control.viewManager.sizes);
}
tryFindVisiblePosition(x, top, bottom) {
let prevResult;
while (true) {
const mid = (top + bottom) / 2;
const pageIndex = this.findPageIndexByOffsetY(mid);
const pageY = this.getPageOffsetY(pageIndex);
const htr = this.calculateHitTestResult(pageIndex, x, mid - pageY);
const rowHeight = htr.row.height;
if (bottom - top < rowHeight)
break;
const halfOfRowHeight = rowHeight / 2;
const y = htr.getLayoutY() + this.getPageOffsetY(htr.page.index) + halfOfRowHeight;
if (htr.detailsLevel >= DocumentLayoutDetailsLevel.Row && y > top && y < bottom) {
if (prevResult?.getPosition() === htr.getPosition())
return htr.getPosition();
prevResult = htr;
}
if (y < mid)
top = mid;
else
bottom = mid;
}
return prevResult ? prevResult.getPosition() : null;
}
calculateHitTestResult(pageIndex, x, y) {
const point = new LayoutPoint(pageIndex, x, y);
const htr = this.control.hitTestManager.calculate(point, DocumentLayoutDetailsLevel.Character, this.selection.activeSubDocument);
if (!this.extendSelection())
htr.correctAsVisibleBox();
return htr;
}
changeSelection(position) {
const selection = this.selection;
if (this.extendSelection())
selection.changeState((newState) => newState.extendLastInterval(position));
else {
const options = new SetSelectionStateOptions();
options.useFieldUiChecks = true;
options.correctIntervalDueToTables = true;
options.correctIntervalDueToFields = true;
selection.changeState((newState) => {
newState.setInterval(new FixedInterval(position, 0))
.setKeepX(selection.keepX)
.setEndOfLine(selection.endOfLine)
.setForwardDirection(true);
}, options);
}
}
scrollToPosition(pageIndex, offsetY) {
const page = this.control.layout.pages[pageIndex];
const pageY = this.control.viewManager.sizes.getPageOffsetY(page);
const scrollInfo = new ScrollTopInfo(pageIndex, offsetY - pageY);
const state = new ScrollState().byScrollInfo.setPageInfo(scrollInfo);
this.control.scrollManager.setScroll(state);
}
isEnabled() {
return super.isEnabled() && this.selection.activeSubDocument.isMain();
}
}