From 3fc814731f3de28311657115469dffc81f0f6127 Mon Sep 17 00:00:00 2001 From: tzim Date: Wed, 13 Nov 2013 14:37:31 +0000 Subject: [PATCH] Gestion des evenements Midi --- DMX-2.0/Conduite.cs | 6 +- DMX-2.0/ContextMenuHelper.cs | 90 +++++++++++++++++++++ DMX-2.0/DMX-2.0.csproj | 1 + DMX-2.0/EventManager.cs | 51 +++++++++--- DMX-2.0/MidiEventProvider.cs | 145 ++++++++++++++++++++++++++++------ DMX-2.0/SeqLinUI.cs | 18 +++++ DMX-2.0/SequenceurLineaire.cs | 23 ++++++ 7 files changed, 298 insertions(+), 36 deletions(-) create mode 100644 DMX-2.0/ContextMenuHelper.cs diff --git a/DMX-2.0/Conduite.cs b/DMX-2.0/Conduite.cs index ad3fb6d..c1e002f 100644 --- a/DMX-2.0/Conduite.cs +++ b/DMX-2.0/Conduite.cs @@ -41,7 +41,7 @@ namespace DMX2 Pause = false; - midip = new MidiEventProvider(); + midip = new MidiEventProvider(eventManager); } EventManager eventManager = new EventManager(); @@ -175,8 +175,6 @@ namespace DMX2 TimeSpan deltaT = tickTime - dernierTick; dernierTick = tickTime; - midip.Process(); - if (!Pause) { /* if (deltaT > TimeSpan.FromMilliseconds (15)) @@ -212,6 +210,8 @@ namespace DMX2 // Cette fonction retourne quasi immédiatement, même si il y'a beaucoup a faire sur l'affichage } + EventManager.ProcessEvents(); + if(tickTime - derniereMaj > TimeSpan.FromMilliseconds(50)){ MainWindow.Win.ScheduleUpdate(); derniereMaj = DateTime.Now; diff --git a/DMX-2.0/ContextMenuHelper.cs b/DMX-2.0/ContextMenuHelper.cs new file mode 100644 index 0000000..201d160 --- /dev/null +++ b/DMX-2.0/ContextMenuHelper.cs @@ -0,0 +1,90 @@ +using System; +using Gdk; +using GLib; +using Gtk; + +namespace DMX2 +{ + public class ContextMenuEventArgs : EventArgs + { + private Widget widget; + + public Widget Widget { get { return widget; } } + + private bool rightClick; + + public bool RightClick { get { return rightClick; } } + + public ContextMenuEventArgs (Widget widget, bool rightClick) + { + this.widget = widget; + this.rightClick = rightClick; + } + } + + public class ContextMenuHelper + { + public event EventHandler ContextMenu; + + public ContextMenuHelper () + { + } + + public ContextMenuHelper (Widget widget) + { + AttachToWidget (widget); + } + + public ContextMenuHelper (Widget widget, EventHandler handler) + { + AttachToWidget (widget); + ContextMenu += handler; + } + + public void AttachToWidget (Widget widget) + { + widget.PopupMenu += Widget_PopupMenu; + widget.ButtonPressEvent += Widget_ButtonPressEvent; + } + + public void DetachFromWidget (Widget widget) + { + widget.PopupMenu -= Widget_PopupMenu; + widget.ButtonPressEvent -= Widget_ButtonPressEvent; + } + + [GLib.ConnectBefore] + private void Widget_PopupMenu (object o, PopupMenuArgs args) + { + RaiseContextMenuEvent (args, (Widget)o, false); + } + + [GLib.ConnectBefore] + private void Widget_ButtonPressEvent (object o, ButtonPressEventArgs args) + { + if (args.Event.Button == 3 && args.Event.Type == EventType.ButtonPress) { + RaiseContextMenuEvent (args, (Widget)o, true); + } + } + + private bool propagating = false; //Prevent reentry + + private void RaiseContextMenuEvent (SignalArgs signalArgs, Widget widget, bool rightClick) + { + if (!propagating) { +//Propagate the event + Event evnt = Gtk.Global.CurrentEvent; + propagating = true; + Gtk.Global.PropagateEvent (widget, evnt); + propagating = false; + signalArgs.RetVal = true; //The widget already processed the event in the propagation + +//Raise the context menu event + ContextMenuEventArgs args = new ContextMenuEventArgs (widget, rightClick); + if (ContextMenu != null) { + ContextMenu.Invoke (this, args); + } + } + } + } +} \ No newline at end of file diff --git a/DMX-2.0/DMX-2.0.csproj b/DMX-2.0/DMX-2.0.csproj index e25a356..a7761a1 100644 --- a/DMX-2.0/DMX-2.0.csproj +++ b/DMX-2.0/DMX-2.0.csproj @@ -105,6 +105,7 @@ + diff --git a/DMX-2.0/EventManager.cs b/DMX-2.0/EventManager.cs index 0cfe52f..2584bc9 100644 --- a/DMX-2.0/EventManager.cs +++ b/DMX-2.0/EventManager.cs @@ -13,10 +13,11 @@ namespace DMX2 public interface IEventProvider { string MenuName{ get; } - string[] GetEventList(); + ICollection GetEventList(); bool Bind (string eventId, IEventTarget target); void Unbind (string eventId, IEventTarget target); - Gtk.Menu GetProviderSubMenu( Gtk.ButtonPressEventHandler handler ); + Gtk.Menu GetProviderSubMenu( EventManager.EventMenuData state, Gtk.ButtonPressEventHandler handler ); + void ProcessEvents(); } public interface IEventTarget @@ -26,6 +27,9 @@ namespace DMX2 public class EventManager { + static public object StateKey = new object(); + static public object EventIdKey = new object(); + class eventBinding { private eventBinding(){} @@ -51,28 +55,57 @@ namespace DMX2 { providers.Add (prov); - List evList = new List(prov.GetEventList()); + //List evList = new List(prov.GetEventList()); foreach (eventBinding b in bindings) { - if(b.provider == null && evList.Contains(b.id)) + if(b.provider == null) { - prov.Bind(b.id,b.target); - b.provider = prov; + if(prov.Bind(b.id,b.target)) + b.provider = prov; } } } - public Gtk.Menu GetMenu ( Gtk.ButtonPressEventHandler handler ) - { - Gtk.Menu menu = new Gtk.Menu(); + public delegate void EventMenuCallBack(object state, string eventId); + public class EventMenuData { + public EventMenuCallBack CallBack; + public object state; + } + public Gtk.Menu GetMenu (object state, EventMenuCallBack 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); + menu.Add(provitem); + } return menu; } + void HandleButtonPressEvent (object o, Gtk.ButtonPressEventArgs args) + { + Gtk.MenuItem item = o as Gtk.MenuItem; + EventMenuData evd = item.Data[EventManager.StateKey] as EventMenuData; + string id = item.Data[EventManager.EventIdKey] as string; + evd.CallBack(evd.state,id); + } + public void ProcessEvents () + { + foreach (IEventProvider prov in providers) { + prov.ProcessEvents(); + } + } public void UnregisterProvider (IEventProvider prov) { diff --git a/DMX-2.0/MidiEventProvider.cs b/DMX-2.0/MidiEventProvider.cs index 7583e41..e504b39 100644 --- a/DMX-2.0/MidiEventProvider.cs +++ b/DMX-2.0/MidiEventProvider.cs @@ -1,36 +1,53 @@ using System; using System.Runtime.InteropServices; +using System.Collections.Generic; namespace DMX2 { public partial class MidiEventProvider : IEventProvider, IDisposable { - IntPtr midi_seq_handle = IntPtr.Zero; - int midiport; + class internalEvent { + public string internalName; + public string description; + List boundTargets=null; - public MidiEventProvider () + public internalEvent(string _id, string _desc) + { + internalName=_id; + description=_desc; + } + public bool HasTargets { + get { + return boundTargets==null?false:boundTargets.Count>0; + } + } + public List BoundTargets { + get { + if(boundTargets==null) boundTargets = new List(); + return boundTargets; + } + } + } + + Dictionary eventlist = new Dictionary(); + + + + IntPtr midi_seq_handle = IntPtr.Zero; + + + public MidiEventProvider (EventManager manager) { snd_seq_open(out midi_seq_handle, "default",SND_SEQ_OPEN_DUPLEX,0); snd_seq_set_client_name(midi_seq_handle,"DMX2"); - midiport = snd_seq_create_simple_port(midi_seq_handle,"dmx_ctrl", + snd_seq_create_simple_port(midi_seq_handle,"dmx_ctrl", SND_SEQ_PORT_CAP_WRITE + SND_SEQ_PORT_CAP_SUBS_WRITE, SND_SEQ_PORT_TYPE_APPLICATION); - Info.Publish(string.Format("Midi port {0}",midiport)); + manager.RegisterProvider(this); } - public void Process () - { - int i; IntPtr ev; - while ((i = snd_seq_event_input_pending(midi_seq_handle,1))>0) { - //Console.WriteLine(i); - i=snd_seq_event_input(midi_seq_handle, out ev); - snd_seq_event_t evS =(snd_seq_event_t) Marshal.PtrToStructure(ev,typeof(snd_seq_event_t)); - Info.Publish(string.Format ("event {0} {1}", evS.type, evS.data_ev_ctrl.value) ); - snd_seq_free_event(ev); - } - } #region IDisposable implementation public void Dispose () @@ -39,33 +56,113 @@ namespace DMX2 } #endregion + #region IEventProvider implementation - string[] IEventProvider.GetEventList () + ICollection IEventProvider.GetEventList () { - throw new System.NotImplementedException (); + return eventlist.Keys; } bool IEventProvider.Bind (string eventId, IEventTarget target) { - throw new System.NotImplementedException (); + if (!eventlist.ContainsKey (eventId)) { + // TODO : check if non received yet midi event... + return false; + } + eventlist[eventId].BoundTargets.Add(target); + return true; } void IEventProvider.Unbind (string eventId, IEventTarget target) { - throw new System.NotImplementedException (); + if (!eventlist.ContainsKey (eventId)) return; + eventlist[eventId].BoundTargets.Remove(target); + return; } - Gtk.Menu IEventProvider.GetProviderSubMenu (Gtk.ButtonPressEventHandler handler) + Gtk.Menu IEventProvider.GetProviderSubMenu (EventManager.EventMenuData state, Gtk.ButtonPressEventHandler handler) { - throw new System.NotImplementedException (); + Gtk.Menu retmenu = new Gtk.Menu (); + //Gtk.MenuItem evmenuitem = new Gtk.MenuItem ("Events"); + //retmenu.Add (evmenuitem); + Gtk.Menu evmenu = retmenu ;// new Gtk.Menu (); + //evmenuitem.Submenu = evmenu; + + List sortedKeys = new List(eventlist.Keys); + sortedKeys.Sort(); + + foreach ( string key in sortedKeys ) { + internalEvent evt= eventlist[key]; + Gtk.MenuItem item = new Gtk.MenuItem(evt.description); + item.Data[EventManager.EventIdKey] = evt.internalName; + item.Data[EventManager.StateKey] = state; + item.ButtonPressEvent += handler; + evmenu.Add (item); + } + + return retmenu; + + } + + void IEventProvider.ProcessEvents () + { + int ret; IntPtr evPtr; + while ((ret = snd_seq_event_input_pending(midi_seq_handle,1))>0) { + ret=snd_seq_event_input(midi_seq_handle, out evPtr); + snd_seq_event_t evS =(snd_seq_event_t) Marshal.PtrToStructure(evPtr,typeof(snd_seq_event_t)); + snd_seq_free_event(evPtr); + + string id=null, description=null; int value=0; + + switch (evS.type) { + case snd_seq_event_type_t.SND_SEQ_EVENT_CONTROLLER: + id= string.Format("MIDI-CTRL-C{0}P{1}",evS.data_ev_ctrl.channel,evS.data_ev_ctrl.param); + description = string.Format("Controller Ch {0} Param {1}",evS.data_ev_ctrl.channel,evS.data_ev_ctrl.param); + value = 255 * evS.data_ev_ctrl.value / 127; + break; + case snd_seq_event_type_t.SND_SEQ_EVENT_NOTEON: + id= string.Format("MIDI-NOTE-C{0}N{1}",evS.data_ev_note.channel, evS.data_ev_note.note ); + description = string.Format("Note {1} Ch {0}",evS.data_ev_note.channel, evS.data_ev_note.note ); + value = 255 ; + break; + case snd_seq_event_type_t.SND_SEQ_EVENT_NOTEOFF: + id= string.Format("MIDI-NOTE-C{0}N{1}",evS.data_ev_note.channel, evS.data_ev_note.note ); + description = string.Format("Note {1} Ch {0}",evS.data_ev_note.channel, evS.data_ev_note.note ); + value = 0; + break; + + //TODO : Regarder si d'autres controles interessants. + default: + id= null; + Info.Publish(string.Format ("event {0}", evS.type) ); + break; + } + + if(id!=null) + { + if(!eventlist.ContainsKey(id)) + eventlist.Add(id,new internalEvent(id,description)); + else{ + if(eventlist[id].HasTargets) + { + EventData evData = new EventData(); + evData.id = id; + evData.value = (byte)value; + foreach( IEventTarget t in eventlist[id].BoundTargets) + t.FireEvent(evData); + } + } + } + + } } string IEventProvider.MenuName { get { - throw new System.NotImplementedException (); + return "Midi"; } } - #endregion + #endregion diff --git a/DMX-2.0/SeqLinUI.cs b/DMX-2.0/SeqLinUI.cs index 1006906..8eccda9 100644 --- a/DMX-2.0/SeqLinUI.cs +++ b/DMX-2.0/SeqLinUI.cs @@ -32,6 +32,8 @@ namespace DMX2 } } + + void OnRenameItemButtonPressed (object o, ButtonPressEventArgs args) { var dlg = new Dialog ("Nouveau Nom ?", GetAncestor(Gtk.Window.GType) as Gtk.Window , DialogFlags.Modal); var entry = new Entry (sequenceur.Name); @@ -241,6 +243,21 @@ namespace DMX2 return tirette; } + void TirettePopup (object sender, ContextMenuEventArgs e) + { + Circuit c = e.Widget.Data[circuitKey] as Circuit; + Menu m = Conduite.Courante.EventManager.GetMenu(c,new EventManager.EventMenuCallBack(TirettePopupEnd)); + m.ShowAll(); + m.Popup(); + } + + void TirettePopupEnd (object state, string eventId) + { + Circuit c = state as Circuit; + sequenceur.BindEvent(c,eventId); + Console.WriteLine("{0} bound to {1}", c, eventId ); + } + static Label NouveauLabel () { Label l = new Label(); @@ -286,6 +303,7 @@ namespace DMX2 tirette.Show(); tirette.ValueChanged += TiretteActionee; tirette.Data.Add(circuitKey,c); + new ContextMenuHelper(tirette, new EventHandler(TirettePopup)); tirette.TooltipText = c.Name; diff --git a/DMX-2.0/SequenceurLineaire.cs b/DMX-2.0/SequenceurLineaire.cs index cb7332d..1f26a04 100644 --- a/DMX-2.0/SequenceurLineaire.cs +++ b/DMX-2.0/SequenceurLineaire.cs @@ -362,6 +362,29 @@ namespace DMX2 } } + private class circEvTarget : IEventTarget{ + Circuit c; SequenceurLineaire seq; + public circEvTarget(SequenceurLineaire _seq, Circuit _c){ + c=_c; + seq=_seq; + } + #region IEventTarget implementation + bool IEventTarget.FireEvent (EventData data) + { + seq.ChangeValeur(c,data.value); + return true; + } + #endregion + + } + + public void BindEvent (Circuit c, string eventId) + { + // TODO : plein de trucs + + Conduite.Courante.EventManager.Bind(eventId,new circEvTarget(this,c)); + } + public override void Save (System.Xml.XmlElement parent) { System.Xml.XmlElement el = parent.OwnerDocument.CreateElement ("SequenceurLineaire");