/*
* MathGraph32 Javascript : Software for animating online dynamic mathematics figures
* https://www.mathgraph32.org/
* @Author Yves Biton (yves.biton@sesamath.net)
* @License: GNU AGPLv3 https://www.gnu.org/licenses/agpl-3.0.html
*/
import Color from './types/Color'
import StyleEncadrement from './types/StyleEncadrement'
import CAffLiePt from './objets/CAffLiePt'
import CCommentaire from './objets/CCommentaire'
import CListeObjets from './objets/CListeObjets'
import { addZoomListener, getStr } from './kernel/kernel'
import addQueue from 'src/kernel/addQueue'
export default Gestionnaire
/**
*
* @param {MtgApp} app
* @constructor
*/
function Gestionnaire (app) {
/** @type {MtgApp} */
this.app = app
/** @type {CListeObjets[]} */
this.sauvegarde = [] // Contiendra les CListeObjets des actions sur la figure
/**
* Chaîne décrivant la nature de l'action en cours
* @type {string[]}
*/
this.natureSauvegarde = []
}
Gestionnaire.nombreMaxiAnnulations = 50 // Le nombre maxi d'annulations
Gestionnaire.prototype.initialise = function () {
const app = this.app
const list = app.listePr
this.sauvegarde = []
this.natureSauvegarde = []
this.sauvegarde.push(new CListeObjets())
list.setCopy(this.sauvegarde[0])
this.indiceFigureEnCours = 0
this.indiceDerniereSauvegarde = 0
app.buttonAnnuler.tip = ''
}
Gestionnaire.prototype.metAJourTipIconesAnnulerRefaire = function () {
const app = this.app
app.cacheTip()
if (this.indiceFigureEnCours > 0) {
app.buttonAnnuler.tip = getStr('Annuler') + ' ' +
getStr(this.natureSauvegarde[this.indiceFigureEnCours])
} else app.buttonAnnuler.tip = ''
if (this.indiceFigureEnCours !== this.indiceDerniereSauvegarde) {
app.buttonRefaire.tip = getStr('Refaire') + ' ' +
getStr(this.natureSauvegarde[this.indiceFigureEnCours + 1])
} else app.buttonRefaire.tip = ''
}
/**
* Enregistre la figure
* @param {string} nature chaîne décrivant à la suite de quelle action la figure est enregistrée
* @param {boolean} updateToolbars : on ne met à jour les toolbar de gauche que si updateToolbars est true
*/
Gestionnaire.prototype.enregistreFigureEnCours = function enregistreFigureEnCours (nature, updateToolbars = true) {
const app = this.app
// Modification version 6.3.0 : Si ola boîte d dialogue de protocole est ouverte et qu'on est en traint
// de modifier un objet via sa boîte de dialogue dde modification, on n'enregistre pas la figure.
// Toutes les modifications sont enrégistrées d'un seul coup quand on quitte la boîte de dialogue de protocole.
if (!app.isRunningProtocol) {
app.effaceIndication()
app.doc.setDirty(app.electron, true)
const list = this.app.listePr
// Ajout version 6.3.0
// Par exemple, si une macro incrémente une variable, si on modifie un objet dépendant de cette variable, il doit etre ajouté
// à la liste des objets sur lesquels agit cette macro.
list.metAJourMacros()
// Fin ajout
if (this.indiceFigureEnCours < Gestionnaire.nombreMaxiAnnulations - 1) {
this.indiceFigureEnCours++
this.natureSauvegarde[this.indiceFigureEnCours] = nature
// natureSauvegarde[indiceFigureEnCours] = nature;
this.sauvegarde[this.indiceFigureEnCours] = new CListeObjets()
list.setCopy(this.sauvegarde[this.indiceFigureEnCours])
this.indiceDerniereSauvegarde = this.indiceFigureEnCours
// Il faut mettre à jour les listes maintenues de façon internes par les
// macros
// quand la figure a été modifiée
list.etablitListesInternesMacros()
} else { // Il faut tout décaler et on perd alors la première sauvegarde
for (let i = 1; i < Gestionnaire.nombreMaxiAnnulations; i++) {
this.natureSauvegarde[i - 1] = this.natureSauvegarde[i]
this.sauvegarde[i - 1] = this.sauvegarde[i]
}
this.natureSauvegarde[Gestionnaire.nombreMaxiAnnulations - 1] = nature
this.sauvegarde[Gestionnaire.nombreMaxiAnnulations - 1] = new CListeObjets()
list.setCopy(this.sauvegarde[Gestionnaire.nombreMaxiAnnulations - 1])
}
this.metAJourTipIconesAnnulerRefaire()
if (updateToolbars) app.updateToolsToolBar()
list.initialiseDependances()
// Si la figure est un exercice de construction et si elle a un énoncé, on s'arrange pour que le g element de cet énoncé
// (affichage de texte ou LaTeX) soit le dernier du svg;
this.reclasseEnonce()
}
}
Gestionnaire.prototype.enregistreFigureEnCoursPourZoom = function () {
const nat = 'Zoom'
if (this.indiceFigureEnCours !== 0) {
const ch = this.natureSauvegarde[this.indiceFigureEnCours]
if (ch.indexOf(nat) === 0) {
if (this.indiceFigureEnCours < Gestionnaire.nombreMaxiAnnulations - 1) {
this.indiceFigureEnCours--
}
}
}
this.enregistreFigureEnCours(nat)
}
Gestionnaire.prototype.annulationPossible = function () {
return (this.indiceFigureEnCours > 0)
}
Gestionnaire.prototype.refairePossible = function () {
return (this.indiceFigureEnCours < this.indiceDerniereSauvegarde)
}
Gestionnaire.prototype.annuleAction = function () {
// On englobe dans un try catch pour capturer les erreurs arrivant dans LaboMep quand on ferme la fenêtre
// de l'exercice
try {
const app = this.app
const doc = this.app.doc
let list = doc.listePr
doc.setDirty(app.electron, true)
this.indiceFigureEnCours--
// Ligne suivante ajoutée version 7.3.2 suite rapport bugsnag
app.outilActif.annuleClignotement()
// Modification version 6.3.5 : Il faut appeler app.retireTout() avant list.retireTout()
app.retireTout()
list.retireTout(true)
list = new CListeObjets()
list.associeA(doc)
doc.listePr = list
this.app.listePr = list
this.sauvegarde[this.indiceFigureEnCours].setCopy(list)
list.initialiseDependances() // Ajout version 4.9.7 pour contrer bug aléatoire sur macos d'animation
list.setClone(this.sauvegarde[this.indiceFigureEnCours])
// Il faut mettre à jour les liste maintenues de façon internes par les macros
list.etablitListesInternesMacros()
// Il faut recréer le buffer de traces et éventuellement l'image de fond de la figure
app.prepareTracesEtImageFond()
// list.creePaneVariables doit être appelé après app.prepareTracesEtImageFond car les paneVariables
// sont maintenant des foreign objects du svg de la figure qui sinon seraient masqués par les objets créés par prepareTracesEtImageFond
list.creePaneVariables()
// Il faut recréer les deux affichages de texet utilisés pour la désigantion des objets et les tip d'outils
app.commentaireDesignation = new CCommentaire(list, null, false, Color.red, 0, 0, 0, 6, true, null, 13, StyleEncadrement.Sans,
false, Color.white, CAffLiePt.alignHorCent, CAffLiePt.alignVerTop, '')
// Contrairement à la version Java il faut afficher même vide
app.commentaireDesignation.positionne()
app.commentaireDesignation.affiche(app.svgFigure, false, doc.couleurFond)
//
app.calculateAndDisplay(false)
app.updateToolsToolBar()
app.listePourConst = app.listePourConstruction()
this.metAJourTipIconesAnnulerRefaire()
app.reInitConst() // Pour réinitialiser une éventuelle construction en cours
if (app.cadre) app.createCadre(app.widthCadre, app.heightCadre)
// Si la figure est un exercice de construction et si elle a un énoncé, on s'arrange pour que le g element de cet énoncé
// (affichage de texte ou LaTeX) soit le dernier du svg;
// Si la figure est un exercice de construction et si elle a un énoncé, on s'arrange pour que le g element de cet énoncé
// (affichage de texte ou LaTeX) soit le dernier du svg;
this.reclasseEnonce()
if (app.zoomOnWheel) addZoomListener(doc, app.svgFigure, app.svgGlob)
} catch (e) {
console.error('Erreur dans Annuler de Gestionnaire', e)
}
}
Gestionnaire.prototype.refaitAction = function () {
// On englobe dans un try catch pour capturer les erreurs arrivant dans LaboMep quand on ferme la fenêtre
// de l'exercice
try {
const app = this.app
const doc = app.doc
const list = app.listePr
doc.setDirty(app.electron, true)
this.indiceFigureEnCours++
// Ligne suivante ajoutée version 7.3.2 suite rapport bugsnag
app.outilActif.annuleClignotement()
// Modification version 6.3.5 : Il faut appeler app.retireTout() avant list.retireTout()
app.retireTout()
list.retireTout(true)
doc.listePr = new CListeObjets()
this.sauvegarde[this.indiceFigureEnCours].setCopy(list)
list.setClone(this.sauvegarde[this.indiceFigureEnCours])
list.associeA(doc)
doc.listePr = list
app.listePr = list
list.etablitListesInternesMacros()
// Il faut recréer le buffer de traces et éventuellement l'image de fond de la figure
app.prepareTracesEtImageFond()
// list.creePaneVariables doit être appelé après app.prepareTracesEtImageFond car les paneVariables
// sont maintenant des foreign objects du svg de la figure qui sinon seraient masqués par les objets créés par prepareTracesEtImageFond
list.creePaneVariables()
// Il faut recréer les deux affichages de texet utilisés pour la désigantion des objets et les tip d'outils
app.commentaireDesignation = new CCommentaire(list, null, false, Color.red, 0, 0, 0, 6, true, null, 13, StyleEncadrement.Sans,
false, Color.white, CAffLiePt.alignHorCent, CAffLiePt.alignVerTop, '')
// Contrairement à la version Java il faut afficher même vide
app.commentaireDesignation.positionne()
app.commentaireDesignation.affiche(app.svgFigure, false, doc.couleurFond)
//
app.calculateAndDisplay(false)
app.updateToolsToolBar()
app.listePourConst = app.listePourConstruction()
this.metAJourTipIconesAnnulerRefaire()
app.reInitConst() // Pour réinitialiser une éventuelle construction en cours
if (app.cadre) app.createCadre(app.widthCadre, app.heightCadre)
this.reclasseEnonce()
if (app.zoomOnWheel) addZoomListener(doc, app.svgFigure, app.svgGlob)
} catch (e) {
console.error('Erreur dans Refaire action de Gestionnaire', e)
}
}
// Modifié version 6.4.8 pour être appelé via addQueue car sinon appelé trop tôt et enonce.g est null
/**
* Fonction qui, dans le cas où l'exercice est un exercice de construction et qu'il a un énoncé incorporé à la figure,
* s'arrange pour que le g element de cet enonce soit le dernier g element du SVG de la figure afi qu'il soit toujours
* bien visible.
* La fonction termine son exécution avant que ce soit effectif, utiliser app.ready() pour savoir quand c'est terminé
* @returns {void}
*/
Gestionnaire.prototype.reclasseEnonce = function reclasseEnonce () {
const app = this.app
if (app.estExercice) {
const enonce = app.getEnonce()
if (enonce !== null) {
addQueue(function () {
const svg = app.svgFigure
const g = enonce.g
svg.removeChild(g)
svg.appendChild(g)
})
}
}
}