feat: F4.8a the documentation items in model and file, measured against Java's
New oracle DocuRun on Java's JDocuElement. Italic is kept (the model knew only bold), an item keeps its file's size and font size (Swift's 32 x 24 and 8-72 changed Java's files), an item without a colour is Java's light grey. Java's new items, colour lists, font sizes and styles, the drag's smallest sizes and Java's stacking; document commands for the editor. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
// The documentation items of a document, changed as Java's documentation mode
|
||||
// changes them (JDocuElement, measured with tools/java-oracle's DocuRun): a
|
||||
// new text or rectangle where it is dropped, moved and resized in whole
|
||||
// pixels, its colour, its font size and style, removed. A text's words are
|
||||
// its Y.Text, typed into by everyone at once.
|
||||
|
||||
import * as Y from 'yjs';
|
||||
import {
|
||||
DOCUMENTATION_BLACK,
|
||||
DOCUMENTATION_GREY,
|
||||
DOCUMENTATION_NEW_SIZE,
|
||||
normalizedFrame,
|
||||
type DocumentationColor,
|
||||
type DocumentationFontStyle,
|
||||
type DocumentationItemKind,
|
||||
type Id,
|
||||
type Rect,
|
||||
} from '@mdg-filius/core';
|
||||
import { ROOTS } from './projectDoc.js';
|
||||
|
||||
const docs = (doc: Y.Doc) => doc.getMap<Y.Map<unknown>>(ROOTS.docs);
|
||||
|
||||
/**
|
||||
* A new item, its top left corner at (x, y): 100 × 50, a text empty and black
|
||||
* in Dialog 12, a rectangle grey; after all others in the list, so of its kind
|
||||
* the lowest, as Java adds it.
|
||||
*/
|
||||
export function addDocumentation(doc: Y.Doc, item: { readonly id: Id; readonly kind: DocumentationItemKind; readonly x: number; readonly y: number }, origin: unknown): void {
|
||||
doc.transact(() => {
|
||||
const order = Math.max(-1, ...[...docs(doc).values()].map((each) => each.get('order') as number)) + 1;
|
||||
const color = item.kind === 'text' ? DOCUMENTATION_BLACK : DOCUMENTATION_GREY;
|
||||
const map = new Y.Map<unknown>();
|
||||
map.set('kind', item.kind);
|
||||
map.set('x', Math.round(item.x));
|
||||
map.set('y', Math.round(item.y));
|
||||
map.set('width', DOCUMENTATION_NEW_SIZE.width);
|
||||
map.set('height', DOCUMENTATION_NEW_SIZE.height);
|
||||
map.set('text', new Y.Text(''));
|
||||
map.set('red', color.red);
|
||||
map.set('green', color.green);
|
||||
map.set('blue', color.blue);
|
||||
map.set('alpha', color.alpha);
|
||||
map.set('font', 'Dialog');
|
||||
map.set('size', 12);
|
||||
map.set('bold', false);
|
||||
map.set('italic', false);
|
||||
map.set('order', order);
|
||||
docs(doc).set(item.id, map);
|
||||
}, origin);
|
||||
}
|
||||
|
||||
/** Its place and size, in whole pixels (Java's bounds are ints), inside the editor's world. */
|
||||
export function setDocumentationFrame(doc: Y.Doc, id: Id, frame: Rect, origin: unknown): void {
|
||||
const map = docs(doc).get(id);
|
||||
if (map === undefined) return;
|
||||
const normalized = normalizedFrame({ x: Math.round(frame.x), y: Math.round(frame.y), width: Math.round(frame.width), height: Math.round(frame.height) });
|
||||
doc.transact(() => {
|
||||
for (const key of ['x', 'y', 'width', 'height'] as const) if (map.get(key) !== normalized[key]) map.set(key, normalized[key]);
|
||||
}, origin);
|
||||
}
|
||||
|
||||
export function setDocumentationColor(doc: Y.Doc, id: Id, color: DocumentationColor, origin: unknown): void {
|
||||
const map = docs(doc).get(id);
|
||||
if (map === undefined) return;
|
||||
doc.transact(() => {
|
||||
map.set('red', color.red);
|
||||
map.set('green', color.green);
|
||||
map.set('blue', color.blue);
|
||||
map.set('alpha', color.alpha);
|
||||
}, origin);
|
||||
}
|
||||
|
||||
/** A text's font size, or its style, which replaces the one it had (Java's deriveFont: italic, then bold, is bold). */
|
||||
export function setDocumentationFont(doc: Y.Doc, id: Id, font: { readonly size?: number; readonly style?: DocumentationFontStyle }, origin: unknown): void {
|
||||
const map = docs(doc).get(id);
|
||||
if (map === undefined || map.get('kind') !== 'text') return;
|
||||
doc.transact(() => {
|
||||
if (font.size !== undefined) map.set('size', font.size);
|
||||
if (font.style !== undefined) {
|
||||
map.set('bold', font.style === 'bold');
|
||||
map.set('italic', font.style === 'italic');
|
||||
}
|
||||
}, origin);
|
||||
}
|
||||
|
||||
export function removeDocumentation(doc: Y.Doc, id: Id, origin: unknown): void {
|
||||
doc.transact(() => docs(doc).delete(id), origin);
|
||||
}
|
||||
|
||||
/** A text's words, to type into; undefined for a rectangle or no item. */
|
||||
export function documentationText(doc: Y.Doc, id: Id): Y.Text | undefined {
|
||||
const map = docs(doc).get(id);
|
||||
return map?.get('kind') === 'text' ? (map.get('text') as Y.Text) : undefined;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
// Public surface of the shared document.
|
||||
export * from './commands.js';
|
||||
export * from './documentation.js';
|
||||
export * from './fields.js';
|
||||
export * from './files.js';
|
||||
export * from './janitor.js';
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
// own? }
|
||||
// links id → { order, sourceNode, sourcePort, targetNode, targetPort }
|
||||
// docs id → { kind, x, y, width, height, text, red, green, blue, alpha,
|
||||
// font, size, bold, order }
|
||||
// font, size, bold, italic, order }
|
||||
// archive name → bytes (the project's own Java applications)
|
||||
//
|
||||
// Departures from §5.2, to keep the model whole: a port's settings are the
|
||||
@@ -190,6 +190,7 @@ function documentationMap(item: DocumentationItem): Y.Map<unknown> {
|
||||
map.set('font', item.fontName);
|
||||
map.set('size', item.fontSize);
|
||||
map.set('bold', item.isBold);
|
||||
map.set('italic', item.isItalic);
|
||||
map.set('order', item.order);
|
||||
return map;
|
||||
}
|
||||
@@ -336,6 +337,8 @@ export function readProject(doc: Y.Doc): ImportedProject {
|
||||
fontName: map.get('font') as string,
|
||||
fontSize: map.get('size') as number,
|
||||
isBold: map.get('bold') as boolean,
|
||||
// A document made before F4.8a has no italic.
|
||||
isItalic: map.get('italic') === true,
|
||||
order: map.get('order') as number,
|
||||
})),
|
||||
);
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// so that it can run on every change while someone drags a device.
|
||||
|
||||
import * as Y from 'yjs';
|
||||
import { compareIds, stableGeneratedMacAddress, type DocumentationItemKind, type HostLabelPolicy, type InstallableProgram, type NodeKind } from '@mdg-filius/core';
|
||||
import { inJavaDrawingOrder, stableGeneratedMacAddress, type DocumentationItemKind, type HostLabelPolicy, type InstallableProgram, type NodeKind } from '@mdg-filius/core';
|
||||
import { inOrder, ROOTS } from './projectDoc.js';
|
||||
|
||||
export interface NodeView {
|
||||
@@ -44,6 +44,7 @@ export interface DocumentationView {
|
||||
readonly font: string;
|
||||
readonly size: number;
|
||||
readonly bold: boolean;
|
||||
readonly italic: boolean;
|
||||
readonly order: number;
|
||||
}
|
||||
|
||||
@@ -153,12 +154,11 @@ export function topologyView(doc: Y.Doc): TopologyView {
|
||||
font: item.get('font') as string,
|
||||
size: item.get('size') as number,
|
||||
bold: item.get('bold') as boolean,
|
||||
italic: item.get('italic') === true,
|
||||
order: item.get('order') as number,
|
||||
}));
|
||||
// The model's render order (inDeterministicRenderOrder): rectangles below texts, then by order, then by id.
|
||||
const layer = (item: DocumentationView) => (item.kind === 'rectangle' ? 0 : 1);
|
||||
docs.sort((left, right) => layer(left) - layer(right) || left.order - right.order || compareIds(left.id, right.id));
|
||||
return { nodes, links, docs };
|
||||
// In Java's drawing order, the last on top: texts over rectangles, of one kind the earlier over the later.
|
||||
return { nodes, links, docs: inJavaDrawingOrder(docs) };
|
||||
}
|
||||
|
||||
/** What a computer's desktop needs of the document (Java's GUIDesktopWindow, GUIDesktopPanel). */
|
||||
|
||||
Reference in New Issue
Block a user