loupiottes/DMX-2.0/SequenceurMacro.cs

716 lines
16 KiB
C#

/*
Copyright (C) Arnaud Houdelette 2012-2014
Copyright (C) Emmanuel Langlois 2012-2014
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
using System;
using System.Collections.Generic;
using System.Xml;
using System.Collections.ObjectModel;
using System.Threading;
namespace DMX2
{
public class SequenceurMacro : Sequenceur
{
public class Ligne {
public Ligne(){}
string nom = string.Empty;
TimeSpan top = TimeSpan.MinValue;
string circuits = string.Empty;
int valeur;
TimeSpan temps = TimeSpan.Zero;
public string Nom {
get {
return nom;
}
set {
nom = value;
}
}
public TimeSpan Top {
get {
return top;
}
set {
top = value;
}
}
public string Circuits {
get {
return circuits;
}
set {
circuits = value;
}
}
public int Valeur {
get {
return valeur;
}
set {
valeur = value;
}
}
public TimeSpan Temps {
get {
return temps;
}
set {
temps = value;
}
}
public void Save (XmlElement parent)
{
XmlElement el = parent.OwnerDocument.CreateElement ("Ligne");
parent.AppendChild (el);
el.SetAttribute ("nom", nom);
el.SetAttribute ("top", top.ToString ());
el.SetAttribute ("circuits", circuits);
el.SetAttribute ("valeur", valeur.ToString ());
el.SetAttribute ("temps", temps.ToString ());
}
public static Ligne Load (Conduite c, XmlElement el)
{
Ligne l = new Ligne();
l.nom = el.GetAttribute ("nom");
l.top = TimeSpan.Parse(el.GetAttribute("top"));
l.circuits = el.GetAttribute ("circuits");
l.valeur = int.Parse(el.GetAttribute("valeur"));
l.temps = TimeSpan.Parse(el.GetAttribute("temps"));
return l;
}
}
public class EffetMacro
{
public EffetMacro( TimeSpan tempsTransition, int valeurInitiale, int valeurFinale) {
TempsPasse = TimeSpan.Zero;
TempsTransition = tempsTransition;
ValeurInitiale= valeurInitiale;
ValeurFinale = valeurFinale;
}
public TimeSpan TempsPasse { get; set; }
public TimeSpan TempsTransition { get; set; }
public int ValeurInitiale { get; set; }
public int ValeurFinale { get; set; }
public bool Incremente (TimeSpan delta)
{
TempsPasse += delta;
if (TempsPasse > TempsTransition) {
TempsPasse = TempsTransition;
return true;
}
return false;
}
public int ValeurCourante()
{
double progression = TempsPasse.TotalMilliseconds/TempsTransition.TotalMilliseconds;
return (int)( progression * (ValeurFinale - ValeurInitiale) + ValeurInitiale );
}
}
List<Ligne> lignes = new List<Ligne>();
Ligne aSuivre = null;
Ligne enCours = null;
Ligne ligneMaitre = null;
TimeSpan timeStamp = TimeSpan.Zero;
TimeSpan topSuivant = TimeSpan.Zero;
bool topPresent = false;
List<Circuit> circuitsSeq = new List<Circuit> ();
Dictionary<Circuit,int> valeurscourantes = new Dictionary<Circuit, int> ();
Dictionary<Circuit,EffetMacro> effetsEnCours = new Dictionary<Circuit, EffetMacro>();
actionEventTargetEx masterEventTarget=null;
actionEventTarget goNextEventTarget=null;
actionEventTarget goBackEventTarget=null;
SeqMacroUI ui = null;
bool change = false;
int master = 100;
public int Master {
get {
return master;
}
set {
master = value;
masterEventTarget.FeedBack ();
}
}
bool paused=false;
public bool Paused {
get {
return paused;
}
set {
paused = value;
}
}
public SequenceurMacro ()
{
masterEventTarget = new actionEventTargetEx (
delegate(EventData data) {
Master = 100 * data.value / 255;
return true;
},
delegate{
return Master *255/100;
},
true
);
goNextEventTarget = new actionEventTarget (
delegate(EventData data) {
if(data.value==255) LigneSuivante();
return true;
}
);
goBackEventTarget = new actionEventTarget (
delegate(EventData data) {
if(data.value==255){
if (IndexLigneEnCours > 0) {
IndexLigneaSuivre = IndexLigneEnCours - 1;
LigneSuivante ();
}
}
return true;
}
);
}
public int IndexLigneEnCours
{
get {
if (enCours == null) return -1;
return lignes.IndexOf(enCours);
}
}
public int IndexLigneaSuivre
{
get {
if (aSuivre == null)
return -1;
return lignes.IndexOf (aSuivre);
}
set {
aSuivre = lignes[value];
}
}
public int AjoutLigne (int pos)
{
lock (this) {
lignes.Insert (pos, new Ligne ());
CommandAdd(pos);
return pos;
}
}
public void RetireLigne (int pos)
{
lock (this) {
if (lignes [pos] == enCours) {
enCours = null;
if (pos + 1 < lignes.Count)
aSuivre = lignes [pos + 1];
}
if (lignes [pos] == aSuivre)
aSuivre = null;
lignes.RemoveAt (pos);
CommandRemove(pos);
}
}
public TimeSpan TimeStamp {
get {
return timeStamp;
}
}
public ReadOnlyCollection<Ligne> Lignes {
get {
return lignes.AsReadOnly();
}
}
public ReadOnlyCollection<Circuit> Circuits {
get {
return circuitsSeq.AsReadOnly ();
}
}
public void ChangeCircuits (System.Collections.Generic.List<Circuit> list)
{
foreach (var c in circuitsSeq.ToArray()) {
if (!list.Contains (c))
lock (this) RetireCircuit (c);
}
foreach (var c in list)
if (!circuitsSeq.Contains (c))
lock (this) AjouteCircuit (c);
circuitsSeq = list;
}
void AjouteCircuit (Circuit c)
{
valeurscourantes [c] = 0;
}
void RetireCircuit (Circuit c)
{
circuitsSeq.Remove (c);
valeurscourantes.Remove (c);
}
/*public override void MajCircuitsSupprimes ()
{
lock (this) {
foreach (var c in circuitsSeq.ToArray()) {
if (!Conduite.Courante.Circuits.Contains (c))
RetireCircuit (c);
}
}
}*/
public override int ValeurCircuit (Circuit c)
{
if (!valeurscourantes.ContainsKey (c))
return 0;
if(master !=100)
return valeurscourantes [c] * master /100;
return valeurscourantes [c];
}
public int ValeurBruteCircuit (Circuit c)
{
if (!circuitsSeq.Contains (c))
return 0;
return valeurscourantes [c];
}
public bool EstActif (Circuit c)
{
lock (this)
return effetsEnCours.ContainsKey(c);
}
public override void Tick (TimeSpan time)
{
if (paused)
return;
timeStamp += time;
if (Monitor.TryEnter (this)) {
try {
if (effetsEnCours.Count > 0) {
List<Circuit> circuits = new List<Circuit> (effetsEnCours.Keys);
foreach (Circuit c in circuits) {
if (effetsEnCours [c].Incremente (time)) {
valeurscourantes [c] = effetsEnCours [c].ValeurFinale;
effetsEnCours.Remove (c);
} else {
valeurscourantes [c] = effetsEnCours [c].ValeurCourante ();
}
}
}
while (topPresent && (timeStamp >= topSuivant)) {
LigneSuivante ();
}
} finally {
Monitor.Exit (this);
}
}
}
public void LigneSuivante ()
{
lock (this) {
if(lignes.Count==0) return;
int index;
change = true; topPresent = false;
if(aSuivre==null) // selection souris
{
index = IndexLigneEnCours +1; // Premier effet si aucun précédement
if(index>= lignes.Count) index = 0; // Boucle si arrivé à la fin
enCours = lignes[index];
// Gestion de la Reprise
if(enCours.Circuits.ToLower().Equals("r") && ligneMaitre != null)
enCours = ligneMaitre;
if(enCours.Nom.Length!=0)
{
ligneMaitre = enCours;
timeStamp = TimeSpan.Zero;
}
}
else
{
enCours = aSuivre;
ligneMaitre = enCours;
timeStamp = TimeSpan.Zero;
}
index = IndexLigneEnCours+1;
if(index<lignes.Count)
{
// Si top présent - non negatif
if(lignes[index].Top>= TimeSpan.Zero)
{
topPresent = true;
topSuivant= lignes[index].Top;
}
}
aSuivre = null;
LanceEffetsMacro(false,TimeSpan.Zero);
if(ui!=null)
ui.EffetChange();
}
}
void LanceEffetsMacro (bool ecrase, TimeSpan tempsMatrice)
{
lock (this) {
if (ecrase)
LanceEffetsMacro (enCours.Circuits, enCours.Valeur, tempsMatrice);
else
LanceEffetsMacro (enCours.Circuits, enCours.Valeur, enCours.Temps);
}
}
void LanceEffetsMacro (string circuits, int valeurCible, TimeSpan temps)
{
if(circuits==null)return;
string[] blocs = circuits.Split(',');
foreach (string bloc in blocs) {
string[] circ = bloc.Split('-');
int start, end;
if(! int.TryParse(circ[0], out start))
continue;
if(circ.Length > 1) // on a affaire a un bloc (de plusieurs)
{
if(! int.TryParse(circ[1], out end))
continue;
}
else
end= start;
for( int i = start; i<=end; i++)
{
Circuit c = Conduite.Courante.GetCircuitByID(i);
if(circuitsSeq.Contains(c))
{
lock(this)
effetsEnCours[c] = new EffetMacro(temps,valeurscourantes[c],valeurCible);
}
}
}
}
public bool LigneChange ()
{
if (change) {
change = false;
return true;
}
return false;
}
public override void Save (System.Xml.XmlElement parent)
{
System.Xml.XmlElement el = parent.OwnerDocument.CreateElement ("SequenceurMacro");
System.Xml.XmlElement xmlEl;
parent.AppendChild (el);
el.SetAttribute ("id", ID.ToString ());
el.SetAttribute ("name", Name);
//el.SetAttribute ("master", master.ToString ());
el.AppendChild(xmlEl = parent.OwnerDocument.CreateElement ("Master"));
xmlEl.SetAttribute("value",master.ToString());
Conduite.Courante.EventManager.SaveBindings(xmlEl,masterEventTarget);
xmlEl = parent.OwnerDocument.CreateElement ("EffetSuivant");
if(Conduite.Courante.EventManager.SaveBindings(xmlEl,goNextEventTarget )) el.AppendChild(xmlEl);
xmlEl = parent.OwnerDocument.CreateElement ("EffetPrecedent");
if(Conduite.Courante.EventManager.SaveBindings(xmlEl,goBackEventTarget )) el.AppendChild(xmlEl);
foreach (Circuit c in circuitsSeq) {
el.AppendChild(xmlEl = parent.OwnerDocument.CreateElement ("CircuitSeq"));
xmlEl.SetAttribute("id",c.ID.ToString());
}
foreach (Ligne li in lignes) {
li.Save(el);
}
}
public override SequenceurUI GetUI ()
{
if (ui == null) {
ui = new SeqMacroUI (this);
ui.Destroyed += UiDestroyed;
}
return ui;
}
void UiDestroyed (object sender, EventArgs e)
{
ui = null;
}
public void BindMasterEvent (string eventId)
{
if(eventId.Length==0)
{
Conduite.Courante.EventManager.Unbind(masterEventTarget);
return;
}
Conduite.Courante.EventManager.Bind(eventId,masterEventTarget);
}
public void BindEffetSuivantEvent (string eventId)
{
if (eventId.Length == 0) {
Conduite.Courante.EventManager.Unbind (goNextEventTarget);
return;
}
Conduite.Courante.EventManager.Bind(eventId,goNextEventTarget);
}
public void BindEffetPrecedentEvent (string eventId)
{
if (eventId.Length == 0) {
Conduite.Courante.EventManager.Unbind (goBackEventTarget);
return;
}
Conduite.Courante.EventManager.Bind(eventId,goBackEventTarget);
}
public static new SequenceurMacro Load (Conduite conduite, System.Xml.XmlElement el)
{
SequenceurMacro seq = new SequenceurMacro();
seq.LoadSeq(conduite,el);
return seq;
}
private void LoadSeq (Conduite conduite, System.Xml.XmlElement el)
{
ID = int.Parse (el.GetAttribute ("id"));
Name = el.GetAttribute ("name");
XmlElement xmlE;
if ((xmlE = el["Master"]) != null) {
master = int.Parse (xmlE.TryGetAttribute("value","100"));
foreach(string id in EventManager.LoadBindings(xmlE))
BindMasterEvent(id);
}
else master = int.Parse (el.TryGetAttribute("master","100"));
if ((xmlE = el["EffetSuivant"])!= null)
foreach(string id in EventManager.LoadBindings(xmlE))
BindEffetSuivantEvent(id);
if ((xmlE = el["EffetPrecedent"])!= null)
foreach(string id in EventManager.LoadBindings(xmlE))
BindEffetPrecedentEvent(id);
foreach (var xc in el.GetElementsByTagName("CircuitSeq")) {
System.Xml.XmlElement xcir = xc as System.Xml.XmlElement;
Circuit c = conduite.GetCircuitByID (int.Parse (xcir.GetAttribute ("id")));
circuitsSeq.Add (c);
AjouteCircuit (c);
}
foreach (var xe in el.GetElementsByTagName("Ligne"))
lignes.Add(Ligne.Load(conduite,xe as System.Xml.XmlElement));
}
static System.Text.RegularExpressions.Regex regexCommandeDirecte = new System.Text.RegularExpressions.Regex(
@"(?<circuits>[\d,-]+) (?<valeur>\d+) (?<temps>\d+)",
System.Text.RegularExpressions.RegexOptions.Compiled);
public void CommandDirecte (string text)
{
var cmd = regexCommandeDirecte.Match (text);
if (cmd.Success) {
string circuits = cmd.Groups["circuits"].Value;
int valeur = int.Parse(cmd.Groups["valeur"].Value);
TimeSpan temps = TimeSpan.FromMilliseconds(100* int.Parse(cmd.Groups["temps"].Value));
LanceEffetsMacro(circuits,valeur,temps);
}
}
static System.Text.RegularExpressions.Regex regexCommand1 = new System.Text.RegularExpressions.Regex(
@"(?<effet>\d+)(t(?<transition>\d+))?",
System.Text.RegularExpressions.RegexOptions.Compiled);
static System.Text.RegularExpressions.Regex regexCommand2 = new System.Text.RegularExpressions.Regex(
@"(?<effet>\d+)(?<params>(t\d+)?)?",
System.Text.RegularExpressions.RegexOptions.Compiled);
public override void Command (string command)
{
lock (this) {
var cmd = regexCommand1.Match(command);
if (cmd.Success) {
if (cmd.Groups ["effet"].Success) {
int effet = int.Parse (cmd.Groups ["effet"].Value) - 1;
int transition=-1;
if(effet>=lignes.Count) return;
enCours = lignes[effet];
ligneMaitre = enCours;
timeStamp = TimeSpan.Zero;
topPresent = false;
int index = IndexLigneEnCours+1;
if(index<lignes.Count)
{
// Si top présent - non negatif
if(lignes[index].Top>= TimeSpan.Zero)
{
topPresent = true;
topSuivant= lignes[index].Top;
}
}
aSuivre = null;
if (cmd.Groups ["transition"].Success) {
transition = int.Parse (cmd.Groups ["transition"].Value);
LanceEffetsMacro(true, TimeSpan.FromMilliseconds(transition *100));
}
else
LanceEffetsMacro(false,TimeSpan.Zero);
if(ui!=null) ui.EffetChange();
}
}
}
}
void CommandAdd (int index)
{
lock (Conduite.Courante.SequenceurMaitre) {
string[] commands = Conduite.Courante.SequenceurMaitre.GetCommands (this);
for (int i = 0; i < commands.Length; i++) {
var cmd = regexCommand2.Match(commands[i]);
if(cmd.Success){
int ef = int.Parse(cmd.Groups["effet"].Value);
if (ef-1>index) {
ef++;
commands[i] = ef.ToString() + cmd.Groups["params"].Value;
}
}
}
Conduite.Courante.SequenceurMaitre.SetCommands(this,commands);
}
}
void CommandRemove (int index)
{
lock (Conduite.Courante.SequenceurMaitre) {
string[] commands = Conduite.Courante.SequenceurMaitre.GetCommands (this);
for (int i = 0; i < commands.Length; i++) {
var cmd = regexCommand2.Match(commands[i]);
if(cmd.Success){
int ef = int.Parse(cmd.Groups["effet"].Value);
if (ef-1 == index)
commands[i] = string.Empty;
else if (ef-1>index) {
ef--;
commands[i] = ef.ToString() + cmd.Groups["params"].Value;
}
}
}
Conduite.Courante.SequenceurMaitre.SetCommands(this,commands);
}
}
void CommandSwap (int index)
{
lock (Conduite.Courante.SequenceurMaitre) {
string[] commands = Conduite.Courante.SequenceurMaitre.GetCommands (this);
// numeros a swapper
int a = index+1;
int b = index+2;
for (int i = 0; i < commands.Length; i++) {
var cmd = regexCommand2.Match(commands[i]);
if(cmd.Success){
int ef = int.Parse(cmd.Groups["effet"].Value);
if (ef == a)
commands[i] = b.ToString() + cmd.Groups["params"].Value;
if (ef == b)
commands[i] = a.ToString() + cmd.Groups["params"].Value;
}
}
Conduite.Courante.SequenceurMaitre.SetCommands(this,commands);
}
}
}
}