375 lines
11 KiB
C#
375 lines
11 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.Linq;
|
|
|
|
namespace DMX2
|
|
{
|
|
/// <summary>
|
|
/// Event data : Objet passé aux cibles d'evenements
|
|
/// </summary>
|
|
public struct EventData
|
|
{
|
|
public string id;
|
|
public byte value;
|
|
public byte prev_value ;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Interface pour les fournisseurs d'evenements
|
|
/// </summary>
|
|
public interface IEventProvider
|
|
{
|
|
/// <summary>
|
|
/// Renvoie le nom du sous menu associé au fournisseur d'evenements.
|
|
/// </summary>
|
|
/// <value>
|
|
/// Le nom du menu.
|
|
/// </value>
|
|
string MenuName{ get; }
|
|
|
|
/// <summary>Demande au fournisseur de signaler l'evenement spécifié</summary>
|
|
/// <param name='eventId'>L'id de l'evenement.</param>
|
|
/// <returns><c>true</c> si le fournisseur reconnais l'id</returns>
|
|
bool Bind (string eventId);
|
|
|
|
/// <summary>Signale au fournisseur que l'evenement n'est plus attendu </summary>
|
|
/// <param name='eventId'>L'id de l'evenement.</param>
|
|
void Unbind (string eventId);
|
|
|
|
/// <summary>Demande la construction du sous-menu evenement au fournisseur</summary>
|
|
/// <returns>Le sous menu</returns>
|
|
/// <param name='state'>Un objet qui sera devra etre stocké dans Data[EventManager.StateKey]</param>
|
|
/// <param name='handler'>La delegate qui devra etre associée aux ButtonClickedEvent</param>
|
|
Gtk.Menu GetProviderSubMenu( EventManager.EventMenuData state, Gtk.ButtonPressEventHandler handler );
|
|
|
|
/// <summary>Appelé par le Timer de la conduite</summary>
|
|
/// <param name='callback'>Fonction a appeler pour chaque evenement.</param>
|
|
void ProcessEvents(EventManagerCallback callback);
|
|
|
|
IFeedbackInfo GetFeedbackInfo(string eventId);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Interface pour les recepteurs d'evenements.
|
|
/// </summary>
|
|
public interface IEventTarget
|
|
{
|
|
/// <summary>Fonction appelée lors d'un evenement</summary>
|
|
/// <returns>Vrai si l'evenement est traité</returns>
|
|
/// <param name='data'>Evenement</param>
|
|
bool FireEvent(EventData data);
|
|
|
|
/// <summary>Indique a la cible qu'on lui associe un evenement</summary>
|
|
/// <param name='id'>l'id de l'evenement</param>
|
|
void Bind(string id);
|
|
|
|
/// <summary>Indique a la cible qu'on lui des associe un evenement</summary>
|
|
/// <param name='id'>l'id de l'evenement</param>
|
|
void Unbind(string id);
|
|
|
|
bool CanFeedback{ get; }
|
|
void AddFeedback(IFeedbackInfo info);
|
|
|
|
}
|
|
|
|
public interface IFeedbackInfo {
|
|
bool FeedBack(byte data);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Callback sur evenement.
|
|
/// </summary>
|
|
public delegate void EventManagerCallback(EventData data);
|
|
|
|
|
|
/// <summary>
|
|
/// Callback appele sur clic sur un bouton de menu de choix d'evenement
|
|
/// </summary>
|
|
public delegate void EventManagerMenuCallBack(object state, string eventId);
|
|
|
|
/// <summary>
|
|
/// Cible generique d'evenement.
|
|
/// </summary>
|
|
public class actionEventTarget : IEventTarget {
|
|
public delegate bool EventAction (EventData data);
|
|
EventAction action;
|
|
public actionEventTarget(EventAction _action)
|
|
{
|
|
action=_action;
|
|
}
|
|
#region IEventTarget implementation
|
|
bool IEventTarget.FireEvent (EventData data)
|
|
{
|
|
return action(data);
|
|
}
|
|
|
|
void IEventTarget.Bind (string id){} // Rien a faire ici
|
|
void IEventTarget.Unbind (string id){}
|
|
bool IEventTarget.CanFeedback { get { return false; } }
|
|
void IEventTarget.AddFeedback (IFeedbackInfo info)
|
|
{
|
|
throw new System.NotImplementedException ();
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
/// <summary>
|
|
/// Cible generique d'evenement.
|
|
/// </summary>
|
|
public class actionEventTargetEx : IEventTarget {
|
|
public delegate bool EventAction (EventData data);
|
|
public delegate int GetData();
|
|
EventAction action;
|
|
GetData getdata;
|
|
bool canfeedback=false , nofeedback=false;
|
|
readonly List<IFeedbackInfo> fbInfos = new List<IFeedbackInfo>();
|
|
|
|
public actionEventTargetEx(EventAction _action, GetData _getdata,bool feedback)
|
|
{
|
|
action=_action;
|
|
getdata = _getdata;
|
|
canfeedback = feedback;
|
|
}
|
|
#region IEventTarget implementation
|
|
bool IEventTarget.FireEvent (EventData data)
|
|
{
|
|
int val = getdata();
|
|
|
|
if (
|
|
(data.prev_value < val-5 && data.value < val-5) ||
|
|
(data.prev_value > val+5 && data.value > val+5)
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
nofeedback=true;
|
|
bool res =action(data);
|
|
nofeedback=false;
|
|
return res;
|
|
}
|
|
|
|
public void FeedBack (byte data)
|
|
{
|
|
if (nofeedback)
|
|
return;
|
|
foreach (var info in fbInfos) {
|
|
info.FeedBack(data);
|
|
}
|
|
}
|
|
|
|
void IEventTarget.Bind (string id){} // Rien a faire ici
|
|
void IEventTarget.Unbind (string id){}
|
|
bool IEventTarget.CanFeedback { get { return canfeedback; } }
|
|
void IEventTarget.AddFeedback (IFeedbackInfo info)
|
|
{
|
|
fbInfos.Add(info);
|
|
}
|
|
#endregion
|
|
}
|
|
public class EventManager
|
|
{
|
|
Dictionary<string,eventBinding> bindings = new Dictionary<string,eventBinding>();
|
|
List<IEventProvider> providers = new List<IEventProvider>();
|
|
|
|
class eventBinding
|
|
{
|
|
List<IEventTarget> targets=new List<IEventTarget>();
|
|
public void AddTarget(IEventTarget target)
|
|
{
|
|
if(!targets.Contains(target))
|
|
targets.Add(target);
|
|
}
|
|
public void RemoveTarget(IEventTarget target)
|
|
{
|
|
targets.Remove(target);
|
|
}
|
|
public ICollection<IEventTarget> Targets {
|
|
get {
|
|
return targets;
|
|
}
|
|
}
|
|
}
|
|
|
|
public EventManager ()
|
|
{
|
|
|
|
}
|
|
|
|
public void RegisterProvider (IEventProvider prov)
|
|
{
|
|
providers.Add (prov);
|
|
foreach (var bind in bindings) {
|
|
if (prov.Bind (bind.Key)) {
|
|
IFeedbackInfo info = prov.GetFeedbackInfo(bind.Key);
|
|
if(info!=null)
|
|
foreach(IEventTarget target in bind.Value.Targets)
|
|
if(target.CanFeedback)
|
|
target.AddFeedback(info);
|
|
}
|
|
}
|
|
}
|
|
|
|
#region Menus
|
|
// Cles pour association d'etat au elements de menu
|
|
static public object StateKey = new object();
|
|
static public object EventIdKey = new object();
|
|
|
|
// Objet associe aux menus afin de pourvoir retransmettre les infos au createur du menu
|
|
public class EventMenuData {
|
|
public EventManagerMenuCallBack CallBack;
|
|
public object state;
|
|
}
|
|
|
|
///<summary> Appelé par l'interface. L'objet 'state' sera retransmis tel quel lors de l'appel au callback </summary>
|
|
public Gtk.Menu GetMenu (object state, EventManagerMenuCallBack callback)
|
|
{
|
|
Gtk.Menu menu = new Gtk.Menu ();
|
|
EventMenuData evd = new EventMenuData();
|
|
evd.CallBack = callback;
|
|
evd.state = state;
|
|
|
|
Gtk.ButtonPressEventHandler handler = new Gtk.ButtonPressEventHandler (HandleButtonPressEvent);
|
|
|
|
foreach (IEventProvider prov in providers) {
|
|
Gtk.MenuItem provitem = new Gtk.MenuItem(prov.MenuName);
|
|
provitem.Submenu = prov.GetProviderSubMenu(evd, handler);
|
|
if(provitem.Submenu!=null) menu.Add(provitem);
|
|
}
|
|
|
|
// Creation de l'element 'Aucun' retournant un ID vide, pour permettre la desassociation
|
|
Gtk.MenuItem itemNone = new Gtk.MenuItem("Aucun");
|
|
itemNone.Data[StateKey] = evd;
|
|
itemNone.Data[EventIdKey] = "";
|
|
itemNone.ButtonPressEvent += handler;
|
|
menu.Add(itemNone);
|
|
|
|
return menu;
|
|
|
|
}
|
|
|
|
///<summary> Traitement du clic sur les menus generes au dessus </summary>
|
|
void HandleButtonPressEvent (object o, Gtk.ButtonPressEventArgs args)
|
|
{
|
|
Gtk.MenuItem item = o as Gtk.MenuItem;
|
|
EventMenuData evd = item.Data[EventManager.StateKey] as EventMenuData; // On récupere l'objet d'etat et la fonction a rappeler
|
|
string id = item.Data[EventManager.EventIdKey] as string; // ainsi que l'id evenement
|
|
evd.CallBack(evd.state,id); // Appel de la fonction
|
|
}
|
|
#endregion
|
|
|
|
///<summary> Appelé par le Timer de la conduite ... appel le traitement pour l'ensemble des fournisseurs </summary>
|
|
public void ProcessEvents ()
|
|
{
|
|
foreach (IEventProvider prov in providers) {
|
|
prov.ProcessEvents(new EventManagerCallback(EventCallBack));
|
|
}
|
|
}
|
|
|
|
public void UnregisterProvider (IEventProvider prov)
|
|
{
|
|
providers.Remove(prov);
|
|
}
|
|
|
|
///<summary> Enregistrement d'une association id => cible
|
|
public bool Bind (string eventId, IEventTarget target)
|
|
{
|
|
if(!bindings.ContainsKey(eventId))
|
|
bindings.Add (eventId,new eventBinding());
|
|
bindings[eventId].AddTarget(target);
|
|
target.Bind(eventId);
|
|
foreach (IEventProvider prov in providers) {
|
|
if(prov.Bind(eventId)) {
|
|
if(target.CanFeedback){
|
|
IFeedbackInfo info = prov.GetFeedbackInfo(eventId);
|
|
if(info!=null) target.AddFeedback(info);
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
///<summary> Desenregistrement de toutes les associations d'une cible</summary>
|
|
public void Unbind (IEventTarget target)
|
|
{
|
|
var q = from bind in bindings where bind.Value.Targets.Contains(target) select bind.Key;
|
|
foreach(string id in q.ToArray())
|
|
Unbind(id,target);
|
|
}
|
|
|
|
///<summary> Desenregistrement d'une association id => cible</summary>
|
|
public void Unbind (string eventId, IEventTarget target)
|
|
{
|
|
if (!bindings.ContainsKey (eventId)) return;
|
|
bindings [eventId].RemoveTarget (target);
|
|
if (bindings [eventId].Targets.Count == 0) {
|
|
bindings.Remove(eventId);
|
|
foreach (IEventProvider prov in providers) {
|
|
prov.Unbind(eventId);
|
|
}
|
|
}
|
|
|
|
target.Unbind(eventId);
|
|
}
|
|
|
|
///<summary> Fonction appelee sur evenement</summary>
|
|
public void EventCallBack (EventData data)
|
|
{
|
|
#if DEBUG
|
|
Console.WriteLine("Event {0} => {1} (last = {2})",data.id,data.value,data.prev_value);
|
|
#endif
|
|
if (bindings.ContainsKey (data.id)) {
|
|
foreach (IEventTarget target in bindings[data.id].Targets) {
|
|
target.FireEvent(data);
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool SaveBindings (System.Xml.XmlElement xmlParent, IEventTarget target)
|
|
{
|
|
bool ret=false;
|
|
System.Xml.XmlElement xmlB;
|
|
var q = from bind in bindings
|
|
where bind.Value.Targets.Contains(target)
|
|
select bind.Key;
|
|
|
|
foreach (string id in q) {
|
|
ret=true;
|
|
xmlParent.AppendChild(xmlB = xmlParent.OwnerDocument.CreateElement("EventBinding"));
|
|
xmlB.SetAttribute("id",id);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
public static string[] LoadBindings (System.Xml.XmlElement xmlParent)
|
|
{
|
|
var all=xmlParent.GetElementsByTagName("EventBinding");
|
|
string[] ret = new string[all.Count]; int index=0;
|
|
foreach (var xb in all) {
|
|
ret[index++] = (xb as System.Xml.XmlElement).GetAttribute("id");
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
}
|
|
}
|
|
|