Skip to content

Commit 1e5a352

Browse files
committed
Prepare for mouseover mask invalidation
1 parent daad4a9 commit 1e5a352

File tree

13 files changed

+85
-65
lines changed

13 files changed

+85
-65
lines changed

TODO.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ Dans les petits plus, mettre en couleur les composants pourrait être intéressa
77

88
## High priority
99

10-
* waypoint positioning when embedded right-click
1110
* New custom components should show up in library even with showonly
1211
* Take undo snapshot after key events too
1312
* Adder orientation
@@ -44,6 +43,7 @@ Dans les petits plus, mettre en couleur les composants pourrait être intéressa
4443

4544
### DONE
4645

46+
* Waypoint positioning when embedded right-click
4747
* Allow non-preset clock periods
4848
* Allow editing custom component
4949
* Copy-paste

simulator/src/LogicEditor.ts

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,7 @@ export class LogicEditor extends HTMLElement implements DrawableParent {
363363

364364
this._actualZoomFactor = clampZoom(newOptions.zoom)
365365

366-
this.editTools.redrawMgr.addReason("options changed", null)
366+
this.editTools.redrawMgr.addReason("options changed", null, true)
367367
}
368368

369369
private setWindowTitleFrom(docName: string | undefined) {
@@ -627,7 +627,7 @@ export class LogicEditor extends HTMLElement implements DrawableParent {
627627
innerScriptElem.remove() // remove the data element to hide the raw data
628628
// do this manually
629629
this.tryLoadCircuitFromData()
630-
this.doRedraw()
630+
this.doRedraw(true)
631631
return true
632632
} else {
633633
return false
@@ -793,7 +793,7 @@ export class LogicEditor extends HTMLElement implements DrawableParent {
793793
}
794794
checkbox.addEventListener("change", this.wrapHandler(() => {
795795
this._options[optionName] = checkbox.checked
796-
this.editTools.redrawMgr.addReason("option changed: " + optionName, null)
796+
this.editTools.redrawMgr.addReason("option changed: " + optionName, null, true)
797797
this.focus()
798798
}))
799799
const section = div(
@@ -828,7 +828,7 @@ export class LogicEditor extends HTMLElement implements DrawableParent {
828828
wireStylePopup.addEventListener("change", this.wrapHandler(() => {
829829
this._options.wireStyle = wireStylePopup.value as WireStyle
830830
this.linkMgr.invalidateAllWirePaths()
831-
this.editTools.redrawMgr.addReason("wire style changed", null)
831+
this.editTools.redrawMgr.addReason("wire style changed", null, true)
832832
}))
833833
settingsPalette.appendChild(
834834
div(
@@ -898,7 +898,7 @@ export class LogicEditor extends HTMLElement implements DrawableParent {
898898
this.setCanvasSize()
899899
LogicEditor.installGlobalListeners()
900900

901-
this.doRedraw()
901+
this.doRedraw(true)
902902
}
903903

904904
private findLightDOMChild<K extends keyof HTMLElementTagNameMap>(tagName: K): HTMLElementTagNameMap[K] | null {
@@ -944,7 +944,7 @@ export class LogicEditor extends HTMLElement implements DrawableParent {
944944
if (canvasContainer !== undefined) {
945945
editor.wrapHandler(() => {
946946
editor.setCanvasSize()
947-
editor.editTools.redrawMgr.addReason("window resized", null)
947+
editor.editTools.redrawMgr.addReason("window resized", null, true)
948948
})()
949949
}
950950
}
@@ -963,7 +963,7 @@ export class LogicEditor extends HTMLElement implements DrawableParent {
963963
for (const editor of LogicEditor._allConnectedEditors) {
964964
editor.wrapHandler(() => {
965965
editor.setCanvasSize()
966-
editor.editTools.redrawMgr.addReason("devicePixelRatio changed", null)
966+
editor.editTools.redrawMgr.addReason("devicePixelRatio changed", null, true)
967967
})()
968968
}
969969
registerPixelRatioListener()
@@ -1003,7 +1003,7 @@ export class LogicEditor extends HTMLElement implements DrawableParent {
10031003

10041004
// console.log(`Display/interaction is ${wantedModeStr} - ${mode}`)
10051005

1006-
this.editTools.redrawMgr.addReason("mode changed", null)
1006+
this.editTools.redrawMgr.addReason("mode changed", null, true)
10071007

10081008
// update mode active button
10091009
this.root.querySelectorAll(".sim-mode-tool").forEach((elem) => {
@@ -1070,7 +1070,7 @@ export class LogicEditor extends HTMLElement implements DrawableParent {
10701070
public setZoomLevel(zoom: number) {
10711071
this._options.zoom = zoom
10721072
this._actualZoomFactor = clampZoom(zoom)
1073-
this.editTools.redrawMgr.addReason("zoom level changed", null)
1073+
this.editTools.redrawMgr.addReason("zoom level changed", null, true)
10741074
}
10751075

10761076
public updateCustomComponentButtons() {
@@ -1305,7 +1305,7 @@ export class LogicEditor extends HTMLElement implements DrawableParent {
13051305
this.eventMgr.clearPopperIfNecessary()
13061306
this.eventMgr.updateMouseOver([this.mouseX, this.mouseY], false, false)
13071307
this.editTools.moveMgr.clear()
1308-
this.editTools.redrawMgr.addReason("editor context changed", null)
1308+
this.editTools.redrawMgr.addReason("editor context changed", null, true)
13091309

13101310
this.focus()
13111311
}
@@ -1315,7 +1315,7 @@ export class LogicEditor extends HTMLElement implements DrawableParent {
13151315
if (forceUpdate || changed) {
13161316
this.setToolCursor(MouseActions[action].cursor)
13171317
this._topBar?.updateActiveTool(action)
1318-
this.editTools.redrawMgr.addReason("mouse action changed", null)
1318+
this.editTools.redrawMgr.addReason("mouse action changed", null, false)
13191319
this.editor.focus()
13201320
}
13211321
return changed
@@ -1614,7 +1614,7 @@ export class LogicEditor extends HTMLElement implements DrawableParent {
16141614
if (wasDark) {
16151615
setDarkMode(false, false)
16161616
}
1617-
this.doDrawWithContext(g, width, height, transform, transform, true, true)
1617+
this.doDrawWithContext(g, width, height, transform, transform, true, true, false)
16181618
if (wasDark) {
16191619
setDarkMode(true, false)
16201620
}
@@ -1645,7 +1645,7 @@ export class LogicEditor extends HTMLElement implements DrawableParent {
16451645
const [width, height] = this.guessAdequateCanvasSize(false)
16461646
const id = new DOMMatrix()
16471647
const svgCtx = new SVGRenderingContext({ width, height, metadata })
1648-
this.doDrawWithContext(svgCtx, width, height, id, id, true, true)
1648+
this.doDrawWithContext(svgCtx, width, height, id, id, true, true, false)
16491649
const serializedSVG = svgCtx.getSerializedSvg()
16501650
return Promise.resolve(new Blob([serializedSVG], { type: "image/svg+xml" }))
16511651
}
@@ -1830,16 +1830,16 @@ export class LogicEditor extends HTMLElement implements DrawableParent {
18301830
}
18311831

18321832
const animateWires = this._options.animateWires
1833-
const redrawReasons = redrawMgr.getReasonsAndClear()
1834-
if (redrawReasons === undefined && !animateWires) {
1833+
const redrawInfo = redrawMgr.getReasonsAndClear()
1834+
if (redrawInfo === undefined && !animateWires) {
18351835
return
18361836
}
18371837

18381838
// By now, we know that we have to redraw
18391839

18401840
// we need to reset the promise if we have real redraw reasons, not only
18411841
// a wire animate to run
1842-
if (redrawReasons !== undefined && this._propagationResolve === undefined) {
1842+
if (redrawInfo !== undefined && this._propagationResolve === undefined) {
18431843
// console.log("new propagation promise")
18441844
// means that the promise has been resolved already and we are
18451845
// starting a new cycle, so we reset the promise
@@ -1848,8 +1848,9 @@ export class LogicEditor extends HTMLElement implements DrawableParent {
18481848
})
18491849
}
18501850

1851-
// console.log("Drawing " + (__recalculated ? "with" : "without") + " recalc, reasons:\n " + redrawReasons)
1852-
this.doRedraw()
1851+
const redrawMask = redrawInfo?.[1] ?? false
1852+
// console.log("Drawing " + (__recalculated ? "with" : "without") + " recalc, " + (redrawMask ? "with" : "without") + " redrawing mask, reasons:\n " + (redrawInfo?.[0]() ?? "??"))
1853+
this.doRedraw(redrawMask)
18531854

18541855
if (!redrawMgr.isAnyValuePropagating()) {
18551856
// console.log("No value is propagating")
@@ -1926,11 +1927,11 @@ export class LogicEditor extends HTMLElement implements DrawableParent {
19261927

19271928
public redraw() {
19281929
this.setCanvasSize()
1929-
this.editTools.redrawMgr.addReason("explicit redraw call", null)
1930+
this.editTools.redrawMgr.addReason("explicit redraw call", null, true)
19301931
this.recalcPropagateAndDrawIfNeeded()
19311932
}
19321933

1933-
private doRedraw() {
1934+
private doRedraw(redrawMask: boolean) {
19341935
// const timeBefore = performance.now()
19351936
this._topBar?.updateTimeLabelIfNeeded()
19361937
const g = LogicEditor.getGraphics(this.html.mainCanvas)
@@ -1941,12 +1942,20 @@ export class LogicEditor extends HTMLElement implements DrawableParent {
19411942
const height = mainCanvas.height / baseDrawingScale
19421943
const baseTransform = new DOMMatrix(`scale(${this._baseDrawingScale})`)
19431944
const contentTransform = baseTransform.scale(this._actualZoomFactor)
1944-
this.doDrawWithContext(g, width, height, baseTransform, contentTransform, false, false)
1945+
this.doDrawWithContext(g, width, height, baseTransform, contentTransform, false, false, redrawMask)
19451946
// const timeAfter = performance.now()
19461947
// console.log(`Drawing took ${timeAfter - timeBefore}ms`)
19471948
}
19481949

1949-
private doDrawWithContext(g: GraphicsRendering, width: number, height: number, baseTransform: DOMMatrixReadOnly, contentTransform: DOMMatrixReadOnly, skipBorder: boolean, transparentBackground: boolean) {
1950+
private doDrawWithContext(g: GraphicsRendering, width: number, height: number, baseTransform: DOMMatrixReadOnly, contentTransform: DOMMatrixReadOnly, skipBorder: boolean, transparentBackground: boolean, __redrawMask: boolean) {
1951+
1952+
// TODO handle redrawMask
1953+
// if (redrawMask) {
1954+
// console.log("would redraw mask")
1955+
// } else {
1956+
// console.log("would not redraw mask")
1957+
// }
1958+
19501959
g.setTransform(baseTransform)
19511960
g.lineCap = "square"
19521961
g.textBaseline = "middle"

simulator/src/MoveManager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ export class MoveManager {
5555
const emptyAfter = this._movingDrawables.size === 0
5656
if (emptyBefore !== emptyAfter) {
5757
this.editor.updateCursor(e)
58-
this.editor.editTools.redrawMgr.addReason("started or stopped moving drawables", null)
58+
this.editor.editTools.redrawMgr.addReason("started or stopped moving drawables", null, true)
5959
}
6060
}
6161

simulator/src/RedrawRecalcManager.ts

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5,55 +5,66 @@ import { Dict } from "./utils"
55
export class RedrawManager {
66

77
private _canvasRedrawReasons: Dict<unknown[]> = {}
8+
private _maskWasInvalidated = false
89
private _isPropagating = false
910
private _isEmpty = true
1011

11-
public addReason(reason: string, comp: Drawable | null, isPropagation: boolean = false) {
12+
public addReason(reason: string, comp: Drawable | null, invalidateMask: boolean = false, isPropagation: boolean = false) {
1213
const compObj = comp
1314
const compList = this._canvasRedrawReasons[reason]
1415
if (compList === undefined) {
1516
this._canvasRedrawReasons[reason] = [compObj]
1617
} else {
1718
compList.push(compObj)
1819
}
20+
if (invalidateMask) {
21+
this._maskWasInvalidated = true
22+
}
1923
if (isPropagation) {
2024
this._isPropagating = true
2125
}
2226
this._isEmpty = false
2327
}
2428

25-
public getReasonsAndClear(): string | undefined {
29+
public getReasonsAndClear(): [getReasons: () => string, redrawMask: boolean] | undefined {
2630
if (this._isEmpty) {
2731
return undefined
2832
}
2933

30-
const reasonParts: string[] = []
31-
for (const reason of Object.keys(this._canvasRedrawReasons)) {
32-
reasonParts.push(reason)
33-
const linkedComps = this._canvasRedrawReasons[reason]!
34-
reasonParts.push(" (", String(linkedComps.length), "×)", ": ")
35-
for (const comp of linkedComps) {
36-
if (comp !== null) {
37-
const compAny = comp as any
38-
reasonParts.push(compAny.constructor?.name ?? "Component")
39-
if (compAny.type !== undefined) {
40-
reasonParts.push("_", compAny.type)
41-
}
42-
if (compAny.name !== undefined) {
43-
reasonParts.push("('", compAny.name, "')")
34+
const redrawReasons = this._canvasRedrawReasons
35+
const getReasons = () => {
36+
const reasonParts: string[] = []
37+
for (const reason of Object.keys(redrawReasons)) {
38+
reasonParts.push(reason)
39+
const linkedComps = redrawReasons[reason]!
40+
reasonParts.push(" (", String(linkedComps.length), "×)", ": ")
41+
for (const comp of linkedComps) {
42+
if (comp !== null) {
43+
const compAny = comp as any
44+
reasonParts.push(compAny.constructor?.name ?? "Component")
45+
if (compAny.type !== undefined) {
46+
reasonParts.push("_", compAny.type)
47+
}
48+
if (compAny.name !== undefined) {
49+
reasonParts.push("('", compAny.name, "')")
50+
}
51+
reasonParts.push("; ")
4452
}
45-
reasonParts.push("; ")
4653
}
54+
reasonParts.pop()
55+
reasonParts.push("\n ")
4756
}
4857
reasonParts.pop()
49-
reasonParts.push("\n ")
58+
return reasonParts.join("")
5059
}
51-
reasonParts.pop()
60+
61+
const redrawMask = this._maskWasInvalidated
5262

5363
this._canvasRedrawReasons = {}
5464
this._isPropagating = false
65+
this._maskWasInvalidated = false
5566
this._isEmpty = true
56-
return reasonParts.join("")
67+
return [getReasons, redrawMask]
5768
}
5869

5970
public hasReasons(): boolean {

simulator/src/UIEventManager.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -891,7 +891,7 @@ export class UIEventManager {
891891
const numDeleted = this.editor.editorRoot.components.tryDeleteWhere(cond, onlyOne).length
892892
if (numDeleted > 0) {
893893
this.clearPopperIfNecessary()
894-
this.editor.editTools.redrawMgr.addReason("component(s) deleted", null)
894+
this.editor.editTools.redrawMgr.addReason("component(s) deleted", null, true)
895895
}
896896
return numDeleted
897897
}

simulator/src/components/Component.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,7 +1028,7 @@ export abstract class ComponentBase<
10281028

10291029

10301030
this.parent.ifEditing?.undoMgr.takeSnapshot()
1031-
this.parent.ifEditing?.redrawMgr.addReason("component replaced", newComp)
1031+
this.parent.ifEditing?.redrawMgr.addReason("component replaced", newComp, true)
10321032

10331033
return newComp
10341034
}
@@ -1215,7 +1215,7 @@ export abstract class ComponentBase<
12151215
const deleteItem = MenuData.item("trash", s.Delete, () => {
12161216
const deleted = this.parent.components.tryDelete(this)
12171217
if (deleted) {
1218-
this.setNeedsRedraw("deleted component")
1218+
this.setNeedsRedraw("deleted component", true)
12191219
return InteractionResult.SimpleChange
12201220
}
12211221
return InteractionResult.NoChange

simulator/src/components/DisplayBar.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ export class DisplayBar extends DisplayBarBase<DisplayBarRepr, LogicValue> {
246246
private doSetDisplay(newDisplay: DisplayBarType) {
247247
this._display = newDisplay
248248
this.updateInputOffsetX()
249-
this.setNeedsRedraw("display mode changed")
249+
this.setNeedsRedraw("display mode changed", true)
250250
}
251251

252252
private updateInputOffsetX() {

simulator/src/components/Drawable.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ export abstract class Drawable {
157157

158158
protected constructor(parent: DrawableParent) {
159159
this.parent = parent
160-
this.setNeedsRedraw("newly created")
160+
this.setNeedsRedraw("newly created", true)
161161
}
162162

163163
public get ref() {
@@ -171,8 +171,8 @@ export abstract class Drawable {
171171
this._ref = id
172172
}
173173

174-
protected setNeedsRedraw(reason: string, isPropagation: boolean = false) {
175-
this.parent.ifEditing?.redrawMgr.addReason(reason, this, isPropagation)
174+
protected setNeedsRedraw(reason: string, invalidateMask: boolean = false, isPropagation: boolean = false) {
175+
this.parent.ifEditing?.redrawMgr.addReason(reason, this, invalidateMask, isPropagation)
176176
}
177177

178178
public get drawZIndex(): DrawZIndex {
@@ -476,7 +476,7 @@ export abstract class DrawableWithPosition extends Drawable implements HasPositi
476476

477477
public doSetOrient(newOrient: Orientation) {
478478
this._orient = newOrient
479-
this.setNeedsRedraw("orientation changed")
479+
this.setNeedsRedraw("orientation changed", true)
480480
}
481481

482482
public get width(): number {
@@ -535,7 +535,7 @@ export abstract class DrawableWithPosition extends Drawable implements HasPositi
535535
const delta: [number, number] = [posX - this._posX, posY - this._posY]
536536
this._posX = posX
537537
this._posY = posY
538-
this.setNeedsRedraw("position changed")
538+
this.setNeedsRedraw("position changed", true)
539539
this.positionChanged(delta)
540540
}
541541

simulator/src/components/Label.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,13 @@ export class Label extends ComponentBase<LabelRepr> {
9898
private doSetText(text: string) {
9999
this._text = text
100100
this._cachedTextMetrics = undefined
101-
this.setNeedsRedraw("text changed")
101+
this.setNeedsRedraw("text changed", true)
102102
}
103103

104104
private doSetFont(font: string) {
105105
this._font = font
106106
this._cachedTextMetrics = undefined
107-
this.setNeedsRedraw("font changed")
107+
this.setNeedsRedraw("font changed", true)
108108
}
109109

110110
protected override makeComponentSpecificContextMenuItems(): MenuItems {

simulator/src/components/Output.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ export class Output extends ParametrizedComponentBase<OutputRepr> {
196196
// should never happen, all our inputs are west
197197
return
198198
}
199-
199+
200200
switch (Orientation.add(comp.orient, outNode.orient)) {
201201
case "e":
202202
// nothing to do

0 commit comments

Comments
 (0)