loupiottes/DMX-2.0/SequenceurLineaire.cs
2014-05-15 13:51:04 +00:00

762 lines
19 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.Collections.ObjectModel;
using System.Linq;
using System.Threading;
namespace DMX2
{
public class SequenceurLineaire : Sequenceur
{
public class Effet
{
string _nom;
public Effet (string nom, Dictionary<Circuit,int> valeurs, TimeSpan duree, TimeSpan transition)
{
_nom = nom;
_valeurs = new Dictionary<Circuit, int> (valeurs);
_duree = duree;
_transition = transition;
}
public string Nom {
get {
return _nom;
}
set {
_nom = value;
}
}
Dictionary<Circuit,int> _valeurs;
public int this [Circuit index] {
get {
if (!_valeurs.ContainsKey (index))
_valeurs.Add (index, 0);
return _valeurs [index];
}
}
public Dictionary<Circuit, int> Valeurs {
get {
return _valeurs;
}
}
public void RetireCircuit (Circuit c)
{
_valeurs.Remove (c);
}
TimeSpan _duree = TimeSpan.Zero ;
TimeSpan _transition = TimeSpan.Zero;
public TimeSpan Duree {
get {
return _duree;
}
set {
_duree = value;
}
}
public TimeSpan Transition {
get {
return _transition;
}
set {
_transition = value;
}
}
public void Save (System.Xml.XmlElement parent)
{
System.Xml.XmlElement el = parent.OwnerDocument.CreateElement ("Effet");
System.Xml.XmlElement xmlVal;
parent.AppendChild (el);
el.SetAttribute("nom",_nom);
el.SetAttribute ("duree", _duree.ToString ());
el.SetAttribute ("transition", _transition.ToString ());
foreach (var valeur in _valeurs) {
xmlVal = parent.OwnerDocument.CreateElement("Valeur");
el.AppendChild(xmlVal);
xmlVal.SetAttribute("circuit",valeur.Key.ID.ToString());
xmlVal.SetAttribute("valeur",valeur.Value.ToString());
}
}
public static Effet Load (Conduite conduite, System.Xml.XmlElement el)
{
Dictionary<Circuit, int> valeurs = new Dictionary<Circuit, int> ();
foreach (var xv in el.GetElementsByTagName("Valeur")) {
System.Xml.XmlElement xval = xv as System.Xml.XmlElement;
valeurs.Add(
conduite.GetCircuitByID(int.Parse(xval.GetAttribute("circuit"))),
int.Parse(xval.GetAttribute("valeur"))
);
}
return new Effet( el.GetAttribute("nom"),valeurs,
TimeSpan.Parse(el.GetAttribute("duree")),
TimeSpan.Parse(el.GetAttribute("transition"))
);
}
}
#region EventTargets
class circuitEventTarget : IEventTarget {
Circuit circuit;
Dictionary<string,int> valeursrecues= new Dictionary<string, int>();
SequenceurLineaire seq;
int max=0, signe=-2;
bool attache;
public bool Attache {
get {
return attache;
}
set {
signe=-2;
attache = value;
}
}
public circuitEventTarget(SequenceurLineaire _seq, Circuit _c){
seq=_seq;
circuit=_c;
}
bool IEventTarget.FireEvent (EventData data)
{
valeursrecues[data.id]=data.value;
max = valeursrecues.Values.Max();
if (!Attache) {
int val = seq.ValeurBruteCircuit (circuit);
int cs = Math.Sign (val - max);
if (signe == -2) signe=cs;
if (cs==0 || cs!=signe) Attache=true;
else return true ;
}
seq.ChangeValeur(circuit,max);
return true;
}
void IEventTarget.Bind (string id)
{
valeursrecues[id] = 0;
}
void IEventTarget.Unbind (string id)
{
valeursrecues.Remove(id);
}
List<IFeedbackInfo> feedbacks = new List<IFeedbackInfo>();
bool IEventTarget.CanFeedback { get { return true; } }
void IEventTarget.AddFeedback (IFeedbackInfo info)
{
feedbacks.Add(info);
}
public void FeedBack(byte data){
foreach (var fb in feedbacks)
fb.FeedBack(data);
}
/*IEnumerable<string> IEventTarget.IDs {
get {
return valeursrecues.Keys;
}
}*/
}
#endregion
TimeSpan timeStamp = TimeSpan.Zero;
TimeSpan tempsTransition = TimeSpan.Zero;
List<Effet> effets = new List<Effet> ();
Effet effetcourrant = null;
bool enTransition = false;
bool paused=false;
List<Circuit> circuitsSeq = new List<Circuit> ();
Dictionary<Circuit,int> valeurscourantes = new Dictionary<Circuit, int> ();
Dictionary<Circuit,int> valeursinitiales = new Dictionary<Circuit, int> ();
Dictionary<Circuit,bool> valeurschangees = new Dictionary<Circuit, bool> ();
Dictionary<Circuit,circuitEventTarget> targets = new Dictionary<Circuit, circuitEventTarget>();
actionEventTarget masterEventTarget=null;
actionEventTarget goNextEventTarget=null;
actionEventTarget goBackEventTarget=null;
SeqLinUI ui = null;
int master = 100;
public int Master {
get {
return master;
}
set {
master = value;
}
}
public SequenceurLineaire ()
{
effetcourrant = new Effet ("",valeurscourantes , TimeSpan.Zero, TimeSpan.Zero);
masterEventTarget = new actionEventTarget (
delegate(EventData data) {
Master = 100 * data.value / 255;
return true;
}
);
goNextEventTarget = new actionEventTarget (
delegate(EventData data) {
if(data.value==255) IndexEffetCourrant++;
return true;
}
);
goBackEventTarget = new actionEventTarget (
delegate(EventData data) {
if(data.value==255) IndexEffetCourrant--;
return true;
}
);
}
public TimeSpan TimeStamp {
get {
return timeStamp;
}
}
public ReadOnlyCollection<Circuit> Circuits {
get {
return circuitsSeq.AsReadOnly ();
}
}
public ReadOnlyCollection<Effet> Effets {
get {
return effets.AsReadOnly ();
}
}
public TimeSpan TempsTransition {
get {
return tempsTransition;
}
}
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;
valeursinitiales [c] = 0;
}
void RetireCircuit (Circuit c)
{
foreach (var ef in effets) {
ef.RetireCircuit (c);
}
circuitsSeq.Remove (c);
valeurscourantes.Remove (c);
valeursinitiales.Remove (c);
targets.Remove(c);
}
public override int ValeurCircuit (Circuit c)
{
lock(this) {
if (!valeurscourantes.ContainsKey (c))
return 0;
if (master != 100)
return valeurscourantes [c] * master / 100;
return valeurscourantes [c];
}
}
public int ValeurBruteCircuit (Circuit c)
{
// Appelé par l'interface, donc normalement, uniquement sur les circuits qui composent le sequenceur
//if (!valeurscourantes.ContainsKey (c))
// return 0;
return valeurscourantes [c];
}
public void ChangeValeur (Circuit c, int value)
{
valeurschangees [c] = true;
valeurscourantes [c] = value;
lock(this)
if(targets.ContainsKey(c))
targets[c].FeedBack((byte)value);
}
public bool EstChange (Circuit c)
{
return valeurschangees.ContainsKey (c);
}
public bool EnTransition (Circuit c)
{
if(!enTransition) return false ;
return valeurscourantes [c] != effetcourrant [c];
}
public bool EstCapture (Circuit c)
{
if(!targets.ContainsKey(c)) return false;
return targets[c].Attache;
}
public bool Paused {
get {
return paused;
}
set {
paused = value;
}
}
public override void Tick (TimeSpan time)
{
if (paused)
return;
timeStamp += time;
if (Monitor.TryEnter (this))
try {
if (enTransition) {
if (timeStamp < tempsTransition) {
double progression = timeStamp.TotalMilliseconds / tempsTransition.TotalMilliseconds;
foreach (Circuit c in circuitsSeq) {
if (valeurscourantes [c] != effetcourrant [c] && !valeurschangees.ContainsKey (c)) {
valeurscourantes [c] = (int)(progression * (effetcourrant [c] - valeursinitiales [c]) + valeursinitiales [c]);
if(targets.ContainsKey(c))
targets[c].FeedBack((byte)valeurscourantes [c]);
}
}
} else {
FinDeTransition ();
}
}
if (effetcourrant.Duree != TimeSpan.Zero && timeStamp >= effetcourrant.Duree) {
int index = effets.IndexOf (effetcourrant) + 1;
if (index < effets.Count)
ChangeEffetCourrant (index);
}
} finally {
Monitor.Exit (this);
}
}
public void FinDeTransition ()
{
lock(this) {
enTransition = false;
foreach (Circuit c in circuitsSeq)
if (!valeurschangees.ContainsKey (c)){
valeurscourantes [c] = effetcourrant [c];
if(targets.ContainsKey(c))
targets[c].FeedBack((byte)valeurscourantes [c]);
}
}
}
public SequenceurLineaire.Effet EffetCourrant {
get {
return effetcourrant;
}
}
public int IndexEffetCourrant {
get {
return effets.IndexOf(effetcourrant);
}
set {
if(value>=0 && value < effets.Count)
ChangeEffetCourrant(value);
}
}
void ChangeEffetCourrant (int index)
{
lock (this) {
effetcourrant = effets [index];
valeurschangees.Clear ();
valeursinitiales = new Dictionary<Circuit, int> (valeurscourantes);
tempsTransition = effetcourrant.Transition;
enTransition = true;
timeStamp = TimeSpan.Zero;
if (ui != null)
ui.EffetChange ();
foreach(var t in targets.Values) t.Attache = false;
}
}
public int SauveEffet (string nom, TimeSpan duree, TimeSpan transition)
{
lock (this) {
effets.Add (effetcourrant = new Effet (nom, valeurscourantes, duree, transition));
valeurschangees.Clear ();
return effets.Count-1;
}
}
public int InsereEffetApres (int index, string nom, TimeSpan duree, TimeSpan transition)
{
lock (this) {
int pos = index+1;
if (pos >= effets.Count) return SauveEffet(nom,duree,transition);
effets.Insert (pos,effetcourrant = new Effet (nom, valeurscourantes, duree, transition));
valeurschangees.Clear ();
CommandAdd(index);
return pos;
}
}
public void RemplaceEffet (int index)
{
lock (this) {
Effet ef = effets[index];
effets[index] = new Effet (ef.Nom, valeurscourantes, ef.Duree, ef.Transition);
effetcourrant = effets[index];
valeurschangees.Clear ();
}
}
public void SupprimeEffet (int index)
{
lock (this) {
effets.RemoveAt (index);
CommandRemove(index);
}
}
public int MonteEffet (int index)
{
lock (this) {
if (index >= effets.Count || index < 1)
return index;
Effet ef = effets [index];
effets.RemoveAt (index);
effets.Insert (index - 1, ef);
CommandSwap (index - 1);
return index - 1;
}
}
public int BaisseEffet (int index)
{
lock (this) {
if (index > effets.Count - 2 || index < 0)
return index;
Effet ef = effets [index];
effets.RemoveAt (index);
effets.Insert (index + 1, ef);
CommandSwap(index);
return index + 1;
}
}
/*
private class circEvTarget : IEventTarget{
Circuit c; SequenceurLineaire seq; int s=-2; bool ok=false;
public circEvTarget(SequenceurLineaire _seq, Circuit _c){
c=_c;
seq=_seq;
}
#region IEventTarget implementation
bool IEventTarget.FireEvent (EventData data)
{
if (!ok) {
int val = seq.ValeurBruteCircuit (c);
int cs = Math.Sign (val - data.value);
if (s == -2) s =cs;
if (cs==0 || cs!=s) ok=true;
else return true ;
}
seq.ChangeValeur(c,data.value);
return true;
}
#endregion
}
*/
public void BindCircuitEvent (Circuit c, string eventId)
{
if (eventId.Length == 0) {
if(!targets.ContainsKey(c)) return;
Conduite.Courante.EventManager.Unbind(targets[c]);
targets.Remove(c);
return;
}
if(!targets.ContainsKey(c)) targets[c]=new circuitEventTarget(this,c);
Conduite.Courante.EventManager.Bind(eventId,targets[c]);
}
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 override void Save (System.Xml.XmlElement parent)
{
System.Xml.XmlElement el = parent.OwnerDocument.CreateElement ("SequenceurLineaire");
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());
if(targets.ContainsKey(c))
Conduite.Courante.EventManager.SaveBindings(xmlEl,targets[c]);
}
foreach (Effet ef in effets) {
ef.Save(el);
}
}
public override SequenceurUI GetUI ()
{
if (ui == null) {
ui = new SeqLinUI (this);
ui.Destroyed += UiDestroyed;
}
return ui;
}
void UiDestroyed (object sender, EventArgs e)
{
ui = null;
}
public static new SequenceurLineaire Load (Conduite conduite, System.Xml.XmlElement el)
{
SequenceurLineaire seq = new SequenceurLineaire();
seq.LoadSeq(conduite,el);
return seq;
}
private void LoadSeq (Conduite conduite, System.Xml.XmlElement el)
{
System.Xml.XmlElement xmlE;
ID = int.Parse (el.GetAttribute ("id"));
Name = el.GetAttribute ("name");
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(string id in EventManager.LoadBindings (xcir))
BindCircuitEvent(c,id);
}
foreach (var xe in el.GetElementsByTagName("Effet"))
effets.Add(Effet.Load(conduite,xe as System.Xml.XmlElement));
}
static System.Text.RegularExpressions.Regex regexCommandExec = new System.Text.RegularExpressions.Regex(
@"(?<effet>\d+)(t(?<transition>\d+))?",
System.Text.RegularExpressions.RegexOptions.Compiled);
static System.Text.RegularExpressions.Regex regexCommandProcess = 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 = regexCommandExec.Match(command);
if (cmd.Success) {
if (cmd.Groups ["effet"].Success) {
int effet = int.Parse (cmd.Groups ["effet"].Value) - 1;
if (effet < effets.Count)
ChangeEffetCourrant (effet);
}
if (cmd.Groups ["transition"].Success) {
int transition = int.Parse (cmd.Groups ["transition"].Value);
tempsTransition = TimeSpan.FromMilliseconds( transition *100);
}
}
}
}
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 = regexCommandProcess.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 = regexCommandProcess.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 = regexCommandProcess.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);
}
}
}
}