Making history items being rendered with LaTeX (e.g. positions and properties) asynchronous.

This commit is contained in:
Ad5001 2024-09-16 22:56:54 +02:00
parent 8d6891c4f0
commit 70f1c03cb6
Signed by: Ad5001
GPG key ID: EF45F9C6AFE20160
4 changed files with 73 additions and 25 deletions

View file

@ -116,10 +116,23 @@ Button {
anchors.verticalCenter: parent.verticalCenter anchors.verticalCenter: parent.verticalCenter
visible: !hidden visible: !hidden
font.pixelSize: 14 font.pixelSize: 14
text: historyAction.getHTMLString().replace(/\$\{tag_color\}/g, clr) text: ""
textFormat: Text.RichText textFormat: Text.RichText
clip: true clip: true
wrapMode: Text.WordWrap wrapMode: Text.WordWrap
Component.onCompleted: function() {
// Render HTML, might be string, but could also be a promise
const html = historyAction.getHTMLString()
if(typeof html === "string") {
label.text = html.replace(/\$\{tag_color\}/g, clr)
} else {
// Promise! We need to way to wait for it to be completed.
html.then(rendered => {
label.text = rendered.replace(/\$\{tag_color\}/g, clr)
})
}
}
} }
Rectangle { Rectangle {

View file

@ -109,24 +109,28 @@ export class Action {
* Renders a LaTeX-formatted string to an image and wraps it in an HTML tag in a string. * Renders a LaTeX-formatted string to an image and wraps it in an HTML tag in a string.
* *
* @param {string} latexString - Source string of the latex. * @param {string} latexString - Source string of the latex.
* @returns {string} * @returns {Promise<string>}
*/ */
renderLatexAsHtml(latexString) { renderLatexAsHtml(latexString) {
if(!Latex.enabled) if(!Latex.enabled)
throw new Error("Cannot render an item as LaTeX when LaTeX is disabled.") throw new Error("Cannot render an item as LaTeX when LaTeX is disabled.")
return new Promise(resolve => {
let imgDepth = Modules.History.imageDepth let imgDepth = Modules.History.imageDepth
let { source, width, height } = Latex.renderSync( Latex.requestAsyncRender(
latexString, latexString,
imgDepth * (Modules.History.fontSize + 2), imgDepth * (Modules.History.fontSize + 2),
Modules.History.themeTextColor Modules.History.themeTextColor
) ).then((imgData) => {
return `<img src="${source}" width="${width/imgDepth}" height="${height/imgDepth}" style="vertical-align: middle"/>` const { source, width, height } = imgData
resolve(`<img src="${source}" width="${width/imgDepth}" height="${height/imgDepth}" style="vertical-align: middle"/>`)
})
})
} }
/** /**
* Returns a string with the HTML-formatted description of the action. * Returns a string with the HTML-formatted description of the action.
* *
* @returns {string} * @returns {string|Promise<string>}
*/ */
getHTMLString() { getHTMLString() {
return this.getReadableString() return this.getReadableString()

View file

@ -85,8 +85,9 @@ export default class EditedProperty extends Action {
} }
setReadableValues() { setReadableValues() {
this.prevString = ""; this.prevString = ""
this.nextString = ""; this.nextString = ""
this._renderPromises = []
if(this.propertyType instanceof Object) { if(this.propertyType instanceof Object) {
switch(this.propertyType.type) { switch(this.propertyType.type) {
case "Enum": case "Enum":
@ -118,8 +119,11 @@ export default class EditedProperty extends Action {
this.prevHTML = '<tt style="background: rgba(128,128,128,0.1);">&nbsp;'+this.prevString+'&nbsp;</tt>' this.prevHTML = '<tt style="background: rgba(128,128,128,0.1);">&nbsp;'+this.prevString+'&nbsp;</tt>'
this.nextHTML = '<tt style="background: rgba(128,128,128,0.1);">&nbsp;'+this.nextString+'&nbsp;</tt>' this.nextHTML = '<tt style="background: rgba(128,128,128,0.1);">&nbsp;'+this.nextString+'&nbsp;</tt>'
if(Latex.enabled && typeof this.propertyType == 'object' && this.propertyType.type === "Expression") { if(Latex.enabled && typeof this.propertyType == 'object' && this.propertyType.type === "Expression") {
this.prevHTML= this.renderLatexAsHtml(this.previousValue.latexMarkup) // Store promises so that querying can wait for them to finish.
this.nextHTML= this.renderLatexAsHtml(this.newValue.latexMarkup) this._renderPromises = [
this.renderLatexAsHtml(this.previousValue.latexMarkup).then(prev => this.prevHTML = prev),
this.renderLatexAsHtml(this.newValue.latexMarkup).then(next => this.nextHTML = prev)
]
} }
} }
@ -131,10 +135,21 @@ export default class EditedProperty extends Action {
} }
getHTMLString() { getHTMLString() {
return qsTr('%1 of %2 changed from %3 to %4.') return new Promise(resolve => {
const translation = qsTr('%1 of %2 changed from %3 to %4.')
.arg(this.targetPropertyReadable) .arg(this.targetPropertyReadable)
.arg('<b style="font-size: 15px;">&nbsp;' + this.targetName + '&nbsp;</b>') .arg('<b style="font-size: 15px;">&nbsp;' + this.targetName + '&nbsp;</b>')
.arg(this.prevHTML) // Check if we need to wait for LaTeX HTML to be rendered.
.arg(this.nextHTML) if(this.prevHTML !== undefined && this.nextHTML !== undefined)
resolve(translation.arg(this.prevHTML).arg(this.nextHTML))
else
Promise.all(this._renderPromises).then((rendered) => {
// Rendered are (potentially) two HTML strings which are defined during rendering
this.prevHTML = this.prevHTML ?? rendered[0]
this.nextHTML = this.prevHTML ?? rendered[1]
resolve(translation.arg(this.prevHTML).arg(this.nextHTML))
})
})
} }
} }

View file

@ -61,10 +61,15 @@ export default class EditedPosition extends Action {
setReadableValues() { setReadableValues() {
this.prevString = `(${this.previousXValue.toString()},${this.previousYValue.toString()})` this.prevString = `(${this.previousXValue.toString()},${this.previousYValue.toString()})`
this.nextString = `(${this.newXValue.toString()},${this.newYValue.toString()})` this.nextString = `(${this.newXValue.toString()},${this.newYValue.toString()})`
this._renderPromises = []
// Render as LaTeX // Render as LaTeX
if(Latex.enabled) { if(Latex.enabled) {
this.prevHTML = this.renderLatexAsHtml(`\\left(${this.previousXValue.latexMarkup},${this.previousYValue.latexMarkup}\\right)`) const prevMarkup = `\\left(${this.previousXValue.latexMarkup},${this.previousYValue.latexMarkup}\\right)`
this.nextHTML = this.renderLatexAsHtml(`\\left(${this.newXValue.latexMarkup},${this.newYValue.latexMarkup}\\right)`) const nextMarkup = `\\left(${this.newXValue.latexMarkup},${this.newYValue.latexMarkup}\\right)`
this._renderPromises = [ // Will be taken in promise.all
this.renderLatexAsHtml(prevMarkup),
this.renderLatexAsHtml(nextMarkup)
]
} else { } else {
this.prevHTML = '<tt style="background: rgba(128,128,128,0.1);">&nbsp;'+escapeHTML(this.prevString)+'&nbsp;</tt>' this.prevHTML = '<tt style="background: rgba(128,128,128,0.1);">&nbsp;'+escapeHTML(this.prevString)+'&nbsp;</tt>'
this.nextHTML = '<tt style="background: rgba(128,128,128,0.1);">&nbsp;'+escapeHTML(this.nextString)+'&nbsp;</tt>' this.nextHTML = '<tt style="background: rgba(128,128,128,0.1);">&nbsp;'+escapeHTML(this.nextString)+'&nbsp;</tt>'
@ -85,9 +90,20 @@ export default class EditedPosition extends Action {
} }
getHTMLString() { getHTMLString() {
return qsTr('Position of %1 set from %2 to %3.') return new Promise(resolve => {
const translation = qsTr('Position of %1 set from %2 to %3.')
.arg('<b style="font-size: 15px;">&nbsp;' + this.targetName + '&nbsp;</b>') .arg('<b style="font-size: 15px;">&nbsp;' + this.targetName + '&nbsp;</b>')
.arg(this.prevHTML) // Check if we need to wait for LaTeX HTML to be rendered.
.arg(this.nextHTML) if(this.prevHTML !== undefined && this.nextHTML !== undefined)
resolve(translation.arg(this.prevHTML).arg(this.nextHTML))
else
Promise.all(this._renderPromises).then((rendered) => {
// Rendered are (potentially) two HTML strings which are defined during rendering
this.prevHTML = this.prevHTML ?? rendered[0]
this.nextHTML = this.prevHTML ?? rendered[1]
resolve(translation.arg(this.prevHTML).arg(this.nextHTML))
})
})
} }
} }