diff --git a/Essentials Core/PepperDashEssentialsBase/Touchpanels/TriListExtensions.cs b/Essentials Core/PepperDashEssentialsBase/Touchpanels/TriListExtensions.cs index 690bdacf..63e0b1cb 100644 --- a/Essentials Core/PepperDashEssentialsBase/Touchpanels/TriListExtensions.cs +++ b/Essentials Core/PepperDashEssentialsBase/Touchpanels/TriListExtensions.cs @@ -64,13 +64,20 @@ namespace PepperDash.Essentials.Core } /// - /// + /// Sets an action to a held sig /// - /// - /// - /// - /// + /// The sig public static BoolOutputSig SetSigHeldAction(this BasicTriList tl, uint sigNum, uint heldMs, Action heldAction) + { + return SetSigHeldAction(tl, sigNum, heldMs, heldAction, null); + } + + + /// + /// Sets an action to a held sig as well as a released-without-hold action + /// + /// The sig + public static BoolOutputSig SetSigHeldAction(this BasicTriList tl, uint sigNum, uint heldMs, Action heldAction, Action releaseAction) { CTimer heldTimer = null; return tl.SetBoolSigAction(sigNum, press => @@ -87,10 +94,12 @@ namespace PepperDash.Essentials.Core heldAction(); }, heldMs); } - else if (heldTimer != null) // released + { heldTimer.Stop(); - // could also revise this else to fire a released action as well as cancel the timer + if (releaseAction != null) + releaseAction(); + } }); } @@ -143,5 +152,13 @@ namespace PepperDash.Essentials.Core { return ClearSigAction(tl.StringOutput[sigNum]) as StringOutputSig; } + + /// + /// Helper method to set the value of a bool Sig on tri list + /// + public static void SetBool(this BasicTriList tl, uint sigNum, bool value) + { + tl.BooleanInput[sigNum].BoolValue = value; + } } } \ No newline at end of file diff --git a/Essentials/PepperDashEssentials/Fusion/FusionSystemController.cs b/Essentials/PepperDashEssentials/Fusion/FusionSystemController.cs index 1e314bd6..72577ef4 100644 --- a/Essentials/PepperDashEssentials/Fusion/FusionSystemController.cs +++ b/Essentials/PepperDashEssentials/Fusion/FusionSystemController.cs @@ -41,10 +41,10 @@ namespace PepperDash.Essentials.Fusion StringSigData CurrentRoomSourceNameSig; #region System Info Sigs - StringSigData SystemName; - StringSigData Model; - StringSigData SerialNumber; - StringSigData Uptime; + //StringSigData SystemName; + //StringSigData Model; + //StringSigData SerialNumber; + //StringSigData Uptime; #endregion @@ -966,13 +966,13 @@ namespace PepperDash.Essentials.Fusion } // add xpanel here - if (dev is Crestron.SimplSharpPro.UI.XpanelForSmartGraphics) - { - if (attrNum > 10) - continue; - attrName = "Online - XPanel " + attrNum; - attrNum += 160; - } + //if (dev is Crestron.SimplSharpPro.UI.XpanelForSmartGraphics) + //{ + // if (attrNum > 10) + // continue; + // attrName = "Online - XPanel " + attrNum; + // attrNum += 160; + //} //else if (dev is DisplayBase) diff --git a/Essentials/PepperDashEssentials/PepperDashEssentials.csproj b/Essentials/PepperDashEssentials/PepperDashEssentials.csproj index 4e062dea..aebf06cc 100644 --- a/Essentials/PepperDashEssentials/PepperDashEssentials.csproj +++ b/Essentials/PepperDashEssentials/PepperDashEssentials.csproj @@ -160,19 +160,21 @@ - - - - - - - - - - - - - + + + + + + + + + + + + + + + @@ -187,6 +189,7 @@ + diff --git a/Essentials/PepperDashEssentials/UI/CrestronTouchpanelPropertiesConfig.cs b/Essentials/PepperDashEssentials/UI/CrestronTouchpanelPropertiesConfig.cs new file mode 100644 index 00000000..f327e0d5 --- /dev/null +++ b/Essentials/PepperDashEssentials/UI/CrestronTouchpanelPropertiesConfig.cs @@ -0,0 +1,33 @@ +namespace PepperDash.Essentials +{ + public class CrestronTouchpanelPropertiesConfig + { + public string IpId { get; set; } + public string DefaultRoomKey { get; set; } + public string RoomListKey { get; set; } + public string SgdFile { get; set; } + public string ProjectName { get; set; } + public bool ShowVolumeGauge { get; set; } + public bool UsesSplashPage { get; set; } + public bool ShowDate { get; set; } + public bool ShowTime { get; set; } + public UiSetupPropertiesConfig Setup { get; set; } + + /// + /// The count of sources that will trigger the "additional" arrows to show on the SRL. + /// Defaults to 5 + /// + public int SourcesOverflowCount { get; set; } + + public CrestronTouchpanelPropertiesConfig() + { + SourcesOverflowCount = 5; + } + } + + public class UiSetupPropertiesConfig + { + public bool IsVisible { get; set; } + } + +} \ No newline at end of file diff --git a/Essentials/PepperDashEssentials/UI/DualDisplaySourceSRLController.cs b/Essentials/PepperDashEssentials/UI/DualDisplaySourceSRLController.cs new file mode 100644 index 00000000..c91d72f1 --- /dev/null +++ b/Essentials/PepperDashEssentials/UI/DualDisplaySourceSRLController.cs @@ -0,0 +1,28 @@ +//using System; +//using System.Collections.Generic; +//using System.Linq; +//using System.Text; +//using Crestron.SimplSharp; +//using Crestron.SimplSharpPro; +//using Crestron.SimplSharpPro.DeviceSupport; +//using Crestron.SimplSharpPro.UI; + +//using PepperDash.Essentials.Core; + +//namespace PepperDash.Essentials +//{ +// public class DualDisplaySourceSRLController : SubpageReferenceList +// { +// public DualDisplaySourceSRLController(BasicTriListWithSmartObject triList, +// uint smartObjectId, EssentialsPresentationRoom room) +// : base(triList, smartObjectId, 3, 3, 3) +// { +// var srcList = room.s items.Values.ToList().OrderBy(s => s.Order); +// foreach (var item in srcList) +// { +// GetBoolFeedbackSig(index, 1).UserObject = new Action(routeAction); + +// } +// } +// } +//} \ No newline at end of file diff --git a/Essentials/PepperDashEssentials/UI/EssentialsTouchpanelController.cs b/Essentials/PepperDashEssentials/UI/EssentialsTouchpanelController.cs new file mode 100644 index 00000000..8ad6ab1a --- /dev/null +++ b/Essentials/PepperDashEssentials/UI/EssentialsTouchpanelController.cs @@ -0,0 +1,221 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharp.CrestronIO; +using Crestron.SimplSharpPro; +using Crestron.SimplSharpPro.DeviceSupport; +using Crestron.SimplSharpPro.UI; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.PageManagers; + +namespace PepperDash.Essentials +{ + public class EssentialsTouchpanelController : Device + { + public BasicTriListWithSmartObject Panel { get; private set; } + + public PanelDriverBase PanelDriver { get; private set; } + + CTimer BacklightTransitionedOnTimer; + + public EssentialsTouchpanelController(string key, string name, Tswx52ButtonVoiceControl tsw, + string projectName, string sgdPath) + : base(key, name) + { + Panel = tsw; + tsw.LoadSmartObjects(sgdPath); + tsw.SigChange += new Crestron.SimplSharpPro.DeviceSupport.SigEventHandler(Tsw_SigChange); + } + + /// + /// Config constructor + /// + public EssentialsTouchpanelController(string key, string name, string type, CrestronTouchpanelPropertiesConfig props, uint id) + : base(key, name) + { + AddPostActivationAction(() => + { + Debug.Console(0, this, "post-activation linking"); + type = type.ToLower(); + try + { + if (type == "crestronapp") + { + var app = new CrestronApp(id, Global.ControlSystem); + app.ParameterProjectName.Value = props.ProjectName; + Panel = app; + } + else if (type == "tsw560") + Panel = new Tsw560(id, Global.ControlSystem); + else if (type == "tsw752") + Panel = new Tsw752(id, Global.ControlSystem); + else if (type == "tsw1052") + Panel = new Tsw1052(id, Global.ControlSystem); + else + { + Debug.Console(0, this, "WARNING: Cannot create TSW controller with type '{0}'", type); + return; + } + } + catch (Exception e) + { + Debug.Console(0, this, "WARNING: Cannot create TSW base class. Panel will not function: {0}", e.Message); + return; + } + + // Reserved sigs + if (Panel is TswFt5ButtonSystem) + { + var tsw = Panel as TswFt5ButtonSystem; + tsw.ExtenderSystemReservedSigs.Use(); + tsw.ExtenderSystemReservedSigs.DeviceExtenderSigChange + += ExtenderSystemReservedSigs_DeviceExtenderSigChange; + } + + new CTimer(o => + { + var regSuccess = Panel.Register(); + if (regSuccess != eDeviceRegistrationUnRegistrationResponse.Success) + Debug.Console(0, this, "WARNING: Registration failed. Continuing, but panel may not function: {0}", regSuccess); + + // Give up cleanly if SGD is not present. + var sgdName = @"\NVRAM\Program" + InitialParametersClass.ApplicationNumber + + @"\sgd\" + props.SgdFile; + if (!File.Exists(sgdName)) + { + Debug.Console(0, this, "WARNING: Smart object file '{0}' not present. Exiting TSW load", sgdName); + return; + } + + Panel.LoadSmartObjects(sgdName); + Panel.SigChange += Tsw_SigChange; + + var mainDriver = new EssentialsPanelMainInterfaceDriver(Panel, props); + // Then the AV driver + + // spin up different room drivers depending on room type + var room = DeviceManager.GetDeviceForKey(props.DefaultRoomKey); + if (room is EssentialsHuddleSpaceRoom) + { + Debug.Console(0, this, "Adding huddle space driver"); + var avDriver = new EssentialsHuddlePanelAvFunctionsDriver(mainDriver, props); + avDriver.CurrentRoom = room as EssentialsHuddleSpaceRoom; + avDriver.DefaultRoomKey = props.DefaultRoomKey; + mainDriver.AvDriver = avDriver; + LoadAndShowDriver(mainDriver); // This is a little convoluted. + + if (Panel is TswFt5ButtonSystem) + { + var tsw = Panel as TswFt5ButtonSystem; + // Wire up hard keys + tsw.Power.UserObject = new Action(b => { if (!b) avDriver.PowerButtonPressed(); }); + //tsw.Home.UserObject = new Action(b => { if (!b) HomePressed(); }); + tsw.Up.UserObject = new Action(avDriver.VolumeUpPress); + tsw.Down.UserObject = new Action(avDriver.VolumeDownPress); + tsw.ButtonStateChange += new ButtonEventHandler(Tsw_ButtonStateChange); + } + } + else if (room is EssentialsPresentationRoom) + { + Debug.Console(0, this, "Adding presentation room driver"); + var avDriver = new EssentialsPresentationPanelAvFunctionsDriver(mainDriver, props); + avDriver.CurrentRoom = room as EssentialsPresentationRoom; + avDriver.DefaultRoomKey = props.DefaultRoomKey; + mainDriver.AvDriver = avDriver; + LoadAndShowDriver(mainDriver); + + if (Panel is TswFt5ButtonSystem) + { + var tsw = Panel as TswFt5ButtonSystem; + // Wire up hard keys + tsw.Power.UserObject = new Action(b => { if (!b) avDriver.PowerButtonPressed(); }); + //tsw.Home.UserObject = new Action(b => { if (!b) HomePressed(); }); + tsw.Up.UserObject = new Action(avDriver.VolumeUpPress); + tsw.Down.UserObject = new Action(avDriver.VolumeDownPress); + tsw.ButtonStateChange += new ButtonEventHandler(Tsw_ButtonStateChange); + } + } + else + { + Debug.Console(0, this, "ERROR: Cannot load AvFunctionsDriver for room '{0}'", props.DefaultRoomKey); + } + }, 0); + }); + } + + public void LoadAndShowDriver(PanelDriverBase driver) + { + PanelDriver = driver; + driver.Show(); + } + + void HomePressed() + { + if (BacklightTransitionedOnTimer == null) + PanelDriver.BackButtonPressed(); + } + + + void ExtenderSystemReservedSigs_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, SigEventArgs args) + { + // If the sig is transitioning on, mark it in case it was home button that transitioned it + var blOnSig = (Panel as TswFt5ButtonSystem).ExtenderSystemReservedSigs.BacklightOnFeedback; + if (args.Sig == blOnSig && blOnSig.BoolValue) + { + BacklightTransitionedOnTimer = new CTimer(o => + { + BacklightTransitionedOnTimer = null; + }, 200); + } + } + + public void PulseBool(uint join) + { + var act = Panel.BooleanInput[join].UserObject as Action; + if (act != null) + { + act(true); + act(false); + } + } + + public void SetBoolSig(uint join, bool value) + { + var act = Panel.BooleanInput[join].UserObject as Action; + if (act != null) + act(value); + } + + public void SetIntSig(uint join, ushort value) + { + var act = Panel.BooleanInput[join].UserObject as Action; + if (act != null) + { + act(value); + } + } + + void Tsw_SigChange(object currentDevice, Crestron.SimplSharpPro.SigEventArgs args) + { + if (Debug.Level == 2) + Debug.Console(2, this, "Sig change: {0} {1}={2}", args.Sig.Type, args.Sig.Number, args.Sig.StringValue); + var uo = args.Sig.UserObject; + if (uo is Action) + (uo as Action)(args.Sig.BoolValue); + else if (uo is Action) + (uo as Action)(args.Sig.UShortValue); + else if (uo is Action) + (uo as Action)(args.Sig.StringValue); + } + + void Tsw_ButtonStateChange(GenericBase device, ButtonEventArgs args) + { + var uo = args.Button.UserObject; + if(uo is Action) + (uo as Action)(args.Button.State == eButtonState.Pressed); + } + } +} \ No newline at end of file diff --git a/Essentials/PepperDashEssentials/UI/SubpageReferenceListActivityItem.cs b/Essentials/PepperDashEssentials/UI/SubpageReferenceListActivityItem.cs new file mode 100644 index 00000000..4747a61a --- /dev/null +++ b/Essentials/PepperDashEssentials/UI/SubpageReferenceListActivityItem.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro; +using Crestron.SimplSharpPro.UI; + +using PepperDash.Essentials.Core; + +namespace PepperDash.Essentials +{ + public class SubpageReferenceListActivityItem : SubpageReferenceListItem + { + /// + /// + /// + /// + /// + /// 0=Share, 1=Phone Call, 2=Video Call, 3=End Meeting + /// + public SubpageReferenceListActivityItem(uint index, SubpageReferenceList owner, + ushort buttonMode, Action pressAction) + : base(index, owner) + { + Owner.GetBoolFeedbackSig(Index, 1).UserObject = pressAction; + Owner.UShortInputSig(Index, 1).UShortValue = buttonMode; + } + + /// + /// Called by SRL to release all referenced objects + /// + public override void Clear() + { + Owner.BoolInputSig(Index, 1).UserObject = null; + Owner.UShortInputSig(Index, 1).UShortValue = 0; + } + } +} \ No newline at end of file diff --git a/Essentials/PepperDashEssentials/UI/SubpageReferenceListSourceItem.cs b/Essentials/PepperDashEssentials/UI/SubpageReferenceListSourceItem.cs new file mode 100644 index 00000000..73cc5e71 --- /dev/null +++ b/Essentials/PepperDashEssentials/UI/SubpageReferenceListSourceItem.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro; +using Crestron.SimplSharpPro.UI; + +using PepperDash.Essentials.Core; + +namespace PepperDash.Essentials +{ + public class SubpageReferenceListSourceItem : SubpageReferenceListItem + { + public SourceListItem SourceItem { get; private set; } + + public SubpageReferenceListSourceItem(uint index, SubpageReferenceList owner, + SourceListItem sourceItem, Action routeAction) + : base(index, owner) + { + SourceItem = sourceItem; + owner.GetBoolFeedbackSig(index, 1).UserObject = new Action(routeAction); + owner.StringInputSig(index, 1).StringValue = SourceItem.PreferredName; + } + + public void RegisterForSourceChange(IHasCurrentSourceInfoChange room) + { + room.CurrentSingleSourceChange -= room_CurrentSourceInfoChange; + room.CurrentSingleSourceChange += room_CurrentSourceInfoChange; + } + + void room_CurrentSourceInfoChange(EssentialsRoomBase room, SourceListItem info, ChangeType type) + { + if (type == ChangeType.WillChange && info == SourceItem) + ClearFeedback(); + else if (type == ChangeType.DidChange && info == SourceItem) + SetFeedback(); + } + + /// + /// Called by SRL to release all referenced objects + /// + public override void Clear() + { + Owner.BoolInputSig(Index, 1).UserObject = null; + Owner.StringInputSig(Index, 1).StringValue = ""; + } + + /// + /// Sets the selected feedback on the button + /// + public void SetFeedback() + { + Owner.BoolInputSig(Index, 1).BoolValue = true; + } + + /// + /// Clears the selected feedback on the button + /// + public void ClearFeedback() + { + Owner.BoolInputSig(Index, 1).BoolValue = false; + } + } +} \ No newline at end of file diff --git a/Essentials/PepperDashEssentials/UI Drivers/DualDisplayRouting.cs b/Essentials/PepperDashEssentials/UIDrivers/DualDisplayRouting.cs similarity index 100% rename from Essentials/PepperDashEssentials/UI Drivers/DualDisplayRouting.cs rename to Essentials/PepperDashEssentials/UIDrivers/DualDisplayRouting.cs diff --git a/Essentials/PepperDashEssentials/UI Drivers/EssentialsHuddlePanelAvFunctionsDriver.cs b/Essentials/PepperDashEssentials/UIDrivers/Essentials/EssentialsHuddlePanelAvFunctionsDriver.cs similarity index 93% rename from Essentials/PepperDashEssentials/UI Drivers/EssentialsHuddlePanelAvFunctionsDriver.cs rename to Essentials/PepperDashEssentials/UIDrivers/Essentials/EssentialsHuddlePanelAvFunctionsDriver.cs index 6c599488..6bdab840 100644 --- a/Essentials/PepperDashEssentials/UI Drivers/EssentialsHuddlePanelAvFunctionsDriver.cs +++ b/Essentials/PepperDashEssentials/UIDrivers/Essentials/EssentialsHuddlePanelAvFunctionsDriver.cs @@ -1,970 +1,973 @@ -using System; -using System.Collections.Generic; -using Crestron.SimplSharp; -using Crestron.SimplSharpPro; -using Crestron.SimplSharpPro.UI; - -using PepperDash.Core; -using PepperDash.Essentials.Core; -using PepperDash.Essentials.Core.SmartObjects; -using PepperDash.Essentials.Core.PageManagers; - -namespace PepperDash.Essentials -{ - /// - /// - /// - public class EssentialsHuddlePanelAvFunctionsDriver : PanelDriverBase - { - CrestronTouchpanelPropertiesConfig Config; - - public enum UiDisplayMode - { - PresentationMode, AudioSetup - } - - /// - /// Whether volume ramping from this panel will show the volume - /// gauge popup. - /// - public bool ShowVolumeGauge { get; set; } - - /// - /// The amount of time that the volume buttons stays on screen, in ms - /// - public uint VolumeButtonPopupTimeout - { - get { return VolumeButtonsPopupFeedback.TimeoutMs; } - set { VolumeButtonsPopupFeedback.TimeoutMs = value; } - } - - /// - /// The amount of time that the volume gauge stays on screen, in ms - /// - public uint VolumeGaugePopupTimeout - { - get { return VolumeGaugeFeedback.TimeoutMs; } - set { VolumeGaugeFeedback.TimeoutMs = value; } - } - - /// - /// - /// - public uint PowerOffTimeout { get; set; } - - /// - /// - /// - public string DefaultRoomKey - { - get { return _DefaultRoomKey; } - set - { - _DefaultRoomKey = value; - //CurrentRoom = DeviceManager.GetDeviceForKey(value) as EssentialsHuddleSpaceRoom; - } - } - string _DefaultRoomKey; - - /// - /// - /// - public EssentialsHuddleSpaceRoom CurrentRoom - { - get { return _CurrentRoom; } - set - { - SetCurrentRoom(value); - } - } - EssentialsHuddleSpaceRoom _CurrentRoom; - - /// - /// - /// - uint CurrentInterlockedModalJoin; - - /// - /// For hitting feedback - /// - BoolInputSig ShareButtonSig; - BoolInputSig EndMeetingButtonSig; - - /// - /// Controls the extended period that the volume gauge shows on-screen, - /// as triggered by Volume up/down operations - /// - BoolFeedbackPulseExtender VolumeGaugeFeedback; - - /// - /// Controls the period that the volume buttons show on non-hard-button - /// interfaces - /// - BoolFeedbackPulseExtender VolumeButtonsPopupFeedback; - - /// - /// The parent driver for this - /// - PanelDriverBase Parent; - - /// - /// All children attached to this driver. For hiding and showing as a group. - /// - List ChildDrivers = new List(); - - List CurrentDisplayModeSigsInUse = new List(); - - //// Important smart objects - - /// - /// Smart Object 3200 - /// - SubpageReferenceList SourcesSrl; - - /// - /// Smart Object 15022 - /// - SubpageReferenceList ActivityFooterSrl; - - /// - /// Tracks which audio page group the UI is in - /// - UiDisplayMode CurrentDisplayMode; - - /// - /// The AV page mangagers that have been used, to keep them alive for later - /// - Dictionary PageManagers = new Dictionary(); - - /// - /// Current page manager running for a source - /// - PageManager CurrentSourcePageManager; - - /// - /// Will auto-timeout a power off - /// - CTimer PowerOffTimer; - - ModalDialog PowerDownModal; - - ModalDialog WarmingCoolingModal; - - /// - /// Constructor - /// - public EssentialsHuddlePanelAvFunctionsDriver(PanelDriverBase parent, CrestronTouchpanelPropertiesConfig config) - : base(parent.TriList) - { - Config = config; - Parent = parent; - - SourcesSrl = new SubpageReferenceList(TriList, 3200, 3, 3, 3); - ActivityFooterSrl = new SubpageReferenceList(TriList, 15022, 3, 3, 3); - ShareButtonSig = ActivityFooterSrl.BoolInputSig(1, 1); - - SetupActivityFooterWhenRoomOff(); - - ShowVolumeGauge = true; - - // One-second pulse extender for volume gauge - VolumeGaugeFeedback = new BoolFeedbackPulseExtender(1500); - VolumeGaugeFeedback.Feedback - .LinkInputSig(TriList.BooleanInput[UIBoolJoin.VolumeGaugePopupVisible]); - - VolumeButtonsPopupFeedback = new BoolFeedbackPulseExtender(4000); - VolumeButtonsPopupFeedback.Feedback - .LinkInputSig(TriList.BooleanInput[UIBoolJoin.VolumeButtonPopupVisible]); - - PowerOffTimeout = 30000; - - TriList.StringInput[UIStringJoin.StartActivityText].StringValue = - "Tap Share to begin"; - } - - /// - /// - /// - public override void Show() - { - TriList.BooleanInput[UIBoolJoin.TopBarVisible].BoolValue = true; - TriList.BooleanInput[UIBoolJoin.ActivityFooterVisible].BoolValue = true; - - // Default to showing rooms/sources now. - ShowMode(UiDisplayMode.PresentationMode); - - // Attach actions - TriList.SetSigFalseAction(UIBoolJoin.VolumeButtonPopupPress, VolumeButtonsTogglePress); - - //Interlocked modals - TriList.SetSigFalseAction(UIBoolJoin.InterlockedModalClosePress, HideCurrentInterlockedModal); - TriList.SetSigFalseAction(UIBoolJoin.HelpPress, () => - { - string message = null; - var room = DeviceManager.GetDeviceForKey(Config.DefaultRoomKey) - as EssentialsHuddleSpaceRoom; - if (room != null) - message = room.Config.HelpMessage; - else - message = "Sorry, no help message available. No room connected."; - TriList.StringInput[UIStringJoin.HelpMessage].StringValue = message; - ShowInterlockedModal(UIBoolJoin.HelpPageVisible); - }); - - //TriList.SetSigFalseAction(UIBoolJoin.RoomHeaderButtonPress, () => - // ShowInterlockedModal(UIBoolJoin.RoomHeaderPageVisible)); - - // Setup button - TriList.SetSigHeldAction(UIBoolJoin.GearHeaderButtonPress, 2000, - () => ShowInterlockedModal(UIBoolJoin.TechPanelSetupVisible)); - TriList.SetSigFalseAction(UIBoolJoin.TechPagesExitButton, () => - HideCurrentInterlockedModal()); -#warning This gets overridden by config after NYU demo - if(TriList is CrestronApp) - TriList.BooleanInput[UIBoolJoin.GearButtonVisible].BoolValue = false; - else - TriList.BooleanInput[UIBoolJoin.GearButtonVisible].BoolValue = true; - - // power-related functions - // Note: some of these are not directly-related to the huddle space UI, but are held over - // in case - TriList.SetSigFalseAction(UIBoolJoin.ShowPowerOffPress, PowerButtonPressed); - TriList.SetSigFalseAction(UIBoolJoin.PowerOffMorePress, () => - { - CancelPowerOffTimer(); - TriList.BooleanInput[UIBoolJoin.PowerOffStep1Visible].BoolValue = false; - TriList.BooleanInput[UIBoolJoin.PowerOffStep2Visible].BoolValue = true; - }); - TriList.SetSigFalseAction(UIBoolJoin.DisplayPowerTogglePress, () => - { - if (CurrentRoom != null && CurrentRoom.DefaultDisplay is IPower) - (CurrentRoom.DefaultDisplay as IPower).PowerToggle(); - }); - - base.Show(); - } - - /// - /// Handler for room on/off feedback - /// - /// - /// - //void OnFeedback_OutputChange(object sender, EventArgs e) - //{ - - //} - - public override void Hide() - { - HideAndClearCurrentDisplayModeSigsInUse(); - TriList.BooleanInput[UIBoolJoin.TopBarVisible].BoolValue = false; - TriList.BooleanInput[UIBoolJoin.ActivityFooterVisible].BoolValue = false; - TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = false; - TriList.BooleanInput[UIBoolJoin.TapToBeginVisible].BoolValue = false; - TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false; - //TriList.BooleanInput[UIBoolJoin.StagingPageVisible].BoolValue = false; - VolumeButtonsPopupFeedback.ClearNow(); - //CancelPowerOff(); - - base.Hide(); - } - - /// - /// Shows the various "modes" that this driver controls. Presentation, Setup page - /// - /// - public void ShowMode(UiDisplayMode mode) - { - //Clear whatever is showing now. - HideAndClearCurrentDisplayModeSigsInUse(); - CurrentDisplayMode = mode; - switch (mode) - { - case UiDisplayMode.PresentationMode: - // show start page or staging... - if (CurrentRoom.OnFeedback.BoolValue) - { - TriList.BooleanInput[UIBoolJoin.StagingPageVisible].BoolValue = true; - TriList.BooleanInput[UIBoolJoin.TapToBeginVisible].BoolValue = false; - TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false; - } - else - { - TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = true; - TriList.BooleanInput[UIBoolJoin.TapToBeginVisible].BoolValue = true; - TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false; - } - // Date/time - if (Config.ShowDate && Config.ShowTime) - { - TriList.BooleanInput[UIBoolJoin.DateAndTimeVisible].BoolValue = true; - TriList.BooleanInput[UIBoolJoin.DateOnlyVisible].BoolValue = false; - TriList.BooleanInput[UIBoolJoin.TimeOnlyVisible].BoolValue = false; - } - else - { - TriList.BooleanInput[UIBoolJoin.DateAndTimeVisible].BoolValue = false; - TriList.BooleanInput[UIBoolJoin.DateOnlyVisible].BoolValue = Config.ShowDate; - TriList.BooleanInput[UIBoolJoin.TimeOnlyVisible].BoolValue = Config.ShowTime; - } - - ShowCurrentDisplayModeSigsInUse(); - break; - } - } - - /// - /// When the room is off, set the footer SRL - /// - void SetupActivityFooterWhenRoomOff() - { - ActivityFooterSrl.Clear(); - ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(1, ActivityFooterSrl, 0, - b => { if (!b) ShareButtonPressed(); })); - ActivityFooterSrl.Count = 1; - TriList.UShortInput[UIUshortJoin.PresentationListCaretMode].UShortValue = 0; - ShareButtonSig.BoolValue = false; - } - - /// - /// Sets up the footer SRL for when the room is on - /// - void SetupActivityFooterWhenRoomOn() - { - ActivityFooterSrl.Clear(); - ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(1, ActivityFooterSrl, - 0, null)); - ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(2, ActivityFooterSrl, - 3, b => { if (!b) PowerButtonPressed(); })); - ActivityFooterSrl.Count = 2; - TriList.UShortInput[UIUshortJoin.PresentationListCaretMode].UShortValue = 1; - EndMeetingButtonSig = ActivityFooterSrl.BoolInputSig(2, 1); - ShareButtonSig.BoolValue = CurrentRoom.OnFeedback.BoolValue; - } - - /// - /// Attached to activity list share button - /// - void ShareButtonPressed() - { - ShareButtonSig.BoolValue = true; - TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = false; - TriList.BooleanInput[UIBoolJoin.StagingPageVisible].BoolValue = true; - TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = true; - // Run default source when room is off and share is pressed - if (!CurrentRoom.OnFeedback.BoolValue) - CurrentRoom.RunDefaultRoute(); - } - - void ShowInterlockedModal(uint join) - { - if (CurrentInterlockedModalJoin == join) - HideCurrentInterlockedModal(); - else - { - // sets the sig true if the join is right - TriList.BooleanInput[UIBoolJoin.HelpPageVisible].BoolValue = join == UIBoolJoin.HelpPageVisible; - TriList.BooleanInput[UIBoolJoin.RoomHeaderPageVisible].BoolValue = join == UIBoolJoin.RoomHeaderPageVisible; - TriList.BooleanInput[UIBoolJoin.VolumesPageVisible].BoolValue = join == UIBoolJoin.VolumesPageVisible; - TriList.BooleanInput[UIBoolJoin.TechPanelSetupVisible].BoolValue = join == UIBoolJoin.TechPanelSetupVisible; - CurrentInterlockedModalJoin = join; - } - } - - void HideCurrentInterlockedModal() - { - TriList.BooleanInput[CurrentInterlockedModalJoin].BoolValue = false; - CurrentInterlockedModalJoin = 0; - } - - - /// - /// Shows all sigs that are in CurrentDisplayModeSigsInUse - /// - void ShowCurrentDisplayModeSigsInUse() - { - foreach (var sig in CurrentDisplayModeSigsInUse) - sig.BoolValue = true; - } - - /// - /// Hides all CurrentDisplayModeSigsInUse sigs and clears the array - /// - void HideAndClearCurrentDisplayModeSigsInUse() - { - foreach (var sig in CurrentDisplayModeSigsInUse) - sig.BoolValue = false; - CurrentDisplayModeSigsInUse.Clear(); - } - - /// - /// Send the UI back depending on location, not used in huddle UI - /// - public override void BackButtonPressed() - { - switch (CurrentDisplayMode) - { - case UiDisplayMode.PresentationMode: - //CancelReturnToSourceTimer(); - BackToHome(); - break; - } - } - - /// - /// - /// - void BackToHome() - { - Hide(); - Parent.Show(); - } - - /// - /// Loads the appropriate Sigs into CurrentDisplayModeSigsInUse and shows them - /// - void ShowCurrentSource() - { - if (CurrentRoom.CurrentSourceInfo == null) - return; - - var uiDev = CurrentRoom.CurrentSourceInfo.SourceDevice as IUiDisplayInfo; - PageManager pm = null; - // If we need a page manager, get an appropriate one - if (uiDev != null) - { - TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false; - // Got an existing page manager, get it - if (PageManagers.ContainsKey(uiDev)) - pm = PageManagers[uiDev]; - // Otherwise make an apporiate one - else if (uiDev is ISetTopBoxControls) - //pm = new SetTopBoxMediumPageManager(uiDev as ISetTopBoxControls, TriList); - pm = new SetTopBoxThreePanelPageManager(uiDev as ISetTopBoxControls, TriList); - else if (uiDev is IDiscPlayerControls) - pm = new DiscPlayerMediumPageManager(uiDev as IDiscPlayerControls, TriList); - else - pm = new DefaultPageManager(uiDev, TriList); - PageManagers[uiDev] = pm; - CurrentSourcePageManager = pm; - pm.Show(); - } - } - - /// - /// Called from button presses on source, where We can assume we want - /// to change to the proper screen. - /// - /// The key name of the route to run - void UiSelectSource(string key) - { - // Run the route and when it calls back, show the source - CurrentRoom.RunRouteAction(key, null); - } - - /// - /// - /// - public void PowerButtonPressed() - { - if (!CurrentRoom.OnFeedback.BoolValue - || CurrentRoom.ShutdownPromptTimer.IsRunningFeedback.BoolValue) - return; - - CurrentRoom.StartShutdown(ShutdownType.Manual); - } - - /// - /// - /// - /// - /// - void ShutdownPromptTimer_HasStarted(object sender, EventArgs e) - { - // Do we need to check where the UI is? No? - var timer = CurrentRoom.ShutdownPromptTimer; - EndMeetingButtonSig.BoolValue = true; - ShareButtonSig.BoolValue = false; - - if (CurrentRoom.ShutdownType == ShutdownType.Manual) - { - PowerDownModal = new ModalDialog(TriList); - var message = string.Format("Meeting will end in {0} seconds", CurrentRoom.ShutdownPromptSeconds); - - //// figure out a cleaner way to update gauge - //var gauge = CurrentRoom.ShutdownPromptTimer.PercentFeedback; - //EventHandler gaugeHandler = null; - //gaugeHandler = (o, a) => TriList.UShortInput[ModalDialog.TimerGaugeJoin].UShortValue = - // (ushort)(gauge.UShortValue * 65535 / 100); - //gauge.OutputChange += gaugeHandler; - - // Attach timer things to modal - CurrentRoom.ShutdownPromptTimer.TimeRemainingFeedback.OutputChange += ShutdownPromptTimer_TimeRemainingFeedback_OutputChange; - CurrentRoom.ShutdownPromptTimer.PercentFeedback.OutputChange += ShutdownPromptTimer_PercentFeedback_OutputChange; - - // respond to offs by cancelling dialog - var onFb = CurrentRoom.OnFeedback; - EventHandler offHandler = null; - offHandler = (o, a) => - { - if (!onFb.BoolValue) - { - EndMeetingButtonSig.BoolValue = false; - PowerDownModal.HideDialog(); - onFb.OutputChange -= offHandler; - //gauge.OutputChange -= gaugeHandler; - } - }; - onFb.OutputChange += offHandler; - - PowerDownModal.PresentModalDialog(2, "End Meeting", "Power", message, "Cancel", "End Meeting Now", true, true, - but => - { - if (but != 2) // any button except for End cancels - timer.Cancel(); - else - timer.Finish(); - }); - } - } - - /// - /// - /// - /// - /// - void ShutdownPromptTimer_HasFinished(object sender, EventArgs e) - { - //Debug.Console(2, "*#*UI shutdown prompt finished"); - EndMeetingButtonSig.BoolValue = false; - CurrentRoom.ShutdownPromptTimer.TimeRemainingFeedback.OutputChange -= ShutdownPromptTimer_TimeRemainingFeedback_OutputChange; - CurrentRoom.ShutdownPromptTimer.PercentFeedback.OutputChange -= ShutdownPromptTimer_PercentFeedback_OutputChange; - - } - - /// - /// - /// - /// - /// - void ShutdownPromptTimer_WasCancelled(object sender, EventArgs e) - { - //Debug.Console(2, "*#*UI shutdown prompt cancelled"); - if (PowerDownModal != null) - PowerDownModal.HideDialog(); - EndMeetingButtonSig.BoolValue = false; - ShareButtonSig.BoolValue = CurrentRoom.OnFeedback.BoolValue; - - CurrentRoom.ShutdownPromptTimer.TimeRemainingFeedback.OutputChange += ShutdownPromptTimer_TimeRemainingFeedback_OutputChange; - CurrentRoom.ShutdownPromptTimer.PercentFeedback.OutputChange -= ShutdownPromptTimer_PercentFeedback_OutputChange; - } - - void ShutdownPromptTimer_TimeRemainingFeedback_OutputChange(object sender, EventArgs e) - { - - var message = string.Format("Meeting will end in {0} seconds", (sender as StringFeedback).StringValue); - TriList.StringInput[ModalDialog.MessageTextJoin].StringValue = message; - } - - void ShutdownPromptTimer_PercentFeedback_OutputChange(object sender, EventArgs e) - { - var value = (ushort)((sender as IntFeedback).UShortValue * 65535 / 100); - TriList.UShortInput[ModalDialog.TimerGaugeJoin].UShortValue = value; - } - - /// - /// - /// - void CancelPowerOffTimer() - { - if (PowerOffTimer != null) - { - PowerOffTimer.Stop(); - PowerOffTimer = null; - } - } - - /// - /// - /// - void VolumeButtonsTogglePress() - { - if (VolumeButtonsPopupFeedback.BoolValue) - VolumeButtonsPopupFeedback.ClearNow(); - else - { - // Trigger the popup - VolumeButtonsPopupFeedback.BoolValue = true; - VolumeButtonsPopupFeedback.BoolValue = false; - } - } - - /// - /// - /// - /// - public void VolumeUpPress(bool state) - { - // extend timeouts - if (ShowVolumeGauge) - VolumeGaugeFeedback.BoolValue = state; - VolumeButtonsPopupFeedback.BoolValue = state; - if (CurrentRoom.CurrentVolumeControls != null) - CurrentRoom.CurrentVolumeControls.VolumeUp(state); - } - - /// - /// - /// - /// - public void VolumeDownPress(bool state) - { - // extend timeouts - if (ShowVolumeGauge) - VolumeGaugeFeedback.BoolValue = state; - VolumeButtonsPopupFeedback.BoolValue = state; - if (CurrentRoom.CurrentVolumeControls != null) - CurrentRoom.CurrentVolumeControls.VolumeDown(state); - } - - /// - /// Helper for property setter. Sets the panel to the given room, latching up all functionality - /// - void SetCurrentRoom(EssentialsHuddleSpaceRoom room) - { - if (_CurrentRoom == room) return; - // Disconnect current (probably never called) - if (_CurrentRoom != null) - { - // Disconnect current room - _CurrentRoom.CurrentVolumeDeviceChange -= this.CurrentRoom_CurrentAudioDeviceChange; - ClearAudioDeviceConnections(); - _CurrentRoom.CurrentSingleSourceChange -= this.CurrentRoom_SourceInfoChange; - DisconnectSource(_CurrentRoom.CurrentSourceInfo); - _CurrentRoom.ShutdownPromptTimer.HasStarted -= ShutdownPromptTimer_HasStarted; - _CurrentRoom.ShutdownPromptTimer.HasFinished -= ShutdownPromptTimer_HasFinished; - _CurrentRoom.ShutdownPromptTimer.WasCancelled -= ShutdownPromptTimer_WasCancelled; - - _CurrentRoom.OnFeedback.OutputChange += CurrentRoom_OnFeedback_OutputChange; - _CurrentRoom.IsWarmingUpFeedback.OutputChange -= CurrentRoom_IsWarmingFeedback_OutputChange; - _CurrentRoom.IsCoolingDownFeedback.OutputChange -= IsCoolingDownFeedback_OutputChange; - } - - _CurrentRoom = room; - - if (_CurrentRoom != null) - { - // get the source list config and set up the source list - var config = ConfigReader.ConfigObject.SourceLists; - if (config.ContainsKey(_CurrentRoom.SourceListKey)) - { - var srcList = config[_CurrentRoom.SourceListKey]; - // Setup sources list - uint i = 1; // counter for UI list - foreach (var kvp in srcList) - { - var srcConfig = kvp.Value; - if (!srcConfig.IncludeInSourceList) // Skip sources marked this way - continue; - - var actualSource = DeviceManager.GetDeviceForKey(srcConfig.SourceKey) as Device; - if (actualSource == null) - { - Debug.Console(1, "Cannot assign missing source '{0}' to source UI list", - srcConfig.SourceKey); - continue; - } - var routeKey = kvp.Key; - var item = new SubpageReferenceListSourceItem(i++, SourcesSrl, srcConfig, - b => { if (!b) UiSelectSource(routeKey); }); - SourcesSrl.AddItem(item); // add to the SRL - item.RegisterForSourceChange(_CurrentRoom); - } - SourcesSrl.Count = (ushort)(i - 1); - } - // Name and logo - TriList.StringInput[UIStringJoin.CurrentRoomName].StringValue = _CurrentRoom.Name; - if (_CurrentRoom.LogoUrl == null) - { - TriList.BooleanInput[UIBoolJoin.LogoDefaultVisible].BoolValue = true; - TriList.BooleanInput[UIBoolJoin.LogoUrlVisible].BoolValue = false; - } - else - { - TriList.BooleanInput[UIBoolJoin.LogoDefaultVisible].BoolValue = false; - TriList.BooleanInput[UIBoolJoin.LogoUrlVisible].BoolValue = true; - TriList.StringInput[UIStringJoin.LogoUrl].StringValue = _CurrentRoom.LogoUrl; - } - - // Shutdown timer - _CurrentRoom.ShutdownPromptTimer.HasStarted += ShutdownPromptTimer_HasStarted; - _CurrentRoom.ShutdownPromptTimer.HasFinished += ShutdownPromptTimer_HasFinished; - _CurrentRoom.ShutdownPromptTimer.WasCancelled += ShutdownPromptTimer_WasCancelled; - - // Link up all the change events from the room - _CurrentRoom.OnFeedback.OutputChange += CurrentRoom_OnFeedback_OutputChange; - CurrentRoom_SyncOnFeedback(); - _CurrentRoom.IsWarmingUpFeedback.OutputChange += CurrentRoom_IsWarmingFeedback_OutputChange; - _CurrentRoom.IsCoolingDownFeedback.OutputChange += IsCoolingDownFeedback_OutputChange; - - _CurrentRoom.CurrentVolumeDeviceChange += CurrentRoom_CurrentAudioDeviceChange; - RefreshAudioDeviceConnections(); - _CurrentRoom.CurrentSingleSourceChange += CurrentRoom_SourceInfoChange; - RefreshSourceInfo(); - } - else - { - // Clear sigs that need to be - TriList.StringInput[UIStringJoin.CurrentRoomName].StringValue = "Select a room"; - } - } - - /// - /// For room on/off changes - /// - void CurrentRoom_OnFeedback_OutputChange(object sender, EventArgs e) - { - CurrentRoom_SyncOnFeedback(); - } - - void CurrentRoom_SyncOnFeedback() - { - var value = _CurrentRoom.OnFeedback.BoolValue; - //Debug.Console(2, CurrentRoom, "UI: Is on event={0}", value); - TriList.BooleanInput[UIBoolJoin.RoomIsOn].BoolValue = value; - - if (value) //ON - { - SetupActivityFooterWhenRoomOn(); - TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false; - TriList.BooleanInput[UIBoolJoin.StagingPageVisible].BoolValue = true; - TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = false; - TriList.BooleanInput[UIBoolJoin.VolumeSingleMute1Visible].BoolValue = true; - - } - else - { - SetupActivityFooterWhenRoomOff(); - TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = true; - TriList.BooleanInput[UIBoolJoin.VolumeSingleMute1Visible].BoolValue = false; - TriList.BooleanInput[UIBoolJoin.StagingPageVisible].BoolValue = false; - } - } - - /// - /// - /// - void CurrentRoom_IsWarmingFeedback_OutputChange(object sender, EventArgs e) - { - var value = CurrentRoom.IsWarmingUpFeedback.BoolValue; - //Debug.Console(2, CurrentRoom, "UI: WARMING event={0}", value); - - if (value) - { - WarmingCoolingModal = new ModalDialog(TriList); - WarmingCoolingModal.PresentModalDialog(0, "Powering Up", "Power", "

Room is powering up

Please wait

", - "", "", false, false, null); - } - else - { - if (WarmingCoolingModal != null) - WarmingCoolingModal.CancelDialog(); - } - } - - - void IsCoolingDownFeedback_OutputChange(object sender, EventArgs e) - { - var value = CurrentRoom.IsCoolingDownFeedback.BoolValue; - //Debug.Console(2, CurrentRoom, "UI: Cooldown event={0}", value); - - if (value) - { - WarmingCoolingModal = new ModalDialog(TriList); - WarmingCoolingModal.PresentModalDialog(0, "Shut Down", "Power", "

Room is shutting down

Please wait

", - "", "", false, false, null); - } - else - { - if (WarmingCoolingModal != null) - WarmingCoolingModal.CancelDialog(); - } - } - - /// - /// Hides source for provided source info - /// - /// - void DisconnectSource(SourceListItem previousInfo) - { - if (previousInfo == null) return; - - // Hide whatever is showing - if (IsVisible) - { - if (CurrentSourcePageManager != null) - { - CurrentSourcePageManager.Hide(); - CurrentSourcePageManager = null; - } - } - - if (previousInfo == null) return; - var previousDev = previousInfo.SourceDevice; - - // device type interfaces - if (previousDev is ISetTopBoxControls) - (previousDev as ISetTopBoxControls).UnlinkButtons(TriList); - // common interfaces - if (previousDev is IChannel) - (previousDev as IChannel).UnlinkButtons(TriList); - if (previousDev is IColor) - (previousDev as IColor).UnlinkButtons(TriList); - if (previousDev is IDPad) - (previousDev as IDPad).UnlinkButtons(TriList); - if (previousDev is IDvr) - (previousDev as IDvr).UnlinkButtons(TriList); - if (previousDev is INumericKeypad) - (previousDev as INumericKeypad).UnlinkButtons(TriList); - if (previousDev is IPower) - (previousDev as IPower).UnlinkButtons(TriList); - if (previousDev is ITransport) - (previousDev as ITransport).UnlinkButtons(TriList); - //if (previousDev is IRadio) - // (previousDev as IRadio).UnlinkButtons(this); - } - - /// - /// Refreshes and shows the room's current source - /// - void RefreshSourceInfo() - { - var routeInfo = CurrentRoom.CurrentSourceInfo; - // This will show off popup too - if (this.IsVisible) - ShowCurrentSource(); - - if (routeInfo == null)// || !CurrentRoom.OnFeedback.BoolValue) - { - // Check for power off and insert "Room is off" - TriList.StringInput[UIStringJoin.CurrentSourceName].StringValue = "Room is off"; - TriList.StringInput[UIStringJoin.CurrentSourceIcon].StringValue = "Power"; - this.Hide(); - Parent.Show(); - return; - } - else if (CurrentRoom.CurrentSourceInfo != null) - { - TriList.StringInput[UIStringJoin.CurrentSourceName].StringValue = routeInfo.PreferredName; - TriList.StringInput[UIStringJoin.CurrentSourceIcon].StringValue = routeInfo.Icon; // defaults to "blank" - } - else - { - TriList.StringInput[UIStringJoin.CurrentSourceName].StringValue = "---"; - TriList.StringInput[UIStringJoin.CurrentSourceIcon].StringValue = "Blank"; - } - - // Connect controls - if (routeInfo.SourceDevice != null) - ConnectControlDeviceMethods(routeInfo.SourceDevice); - } - - /// - /// Attach the source to the buttons and things - /// - void ConnectControlDeviceMethods(Device dev) - { - if(dev is ISetTopBoxControls) - (dev as ISetTopBoxControls).LinkButtons(TriList); - if (dev is IChannel) - (dev as IChannel).LinkButtons(TriList); - if (dev is IColor) - (dev as IColor).LinkButtons(TriList); - if (dev is IDPad) - (dev as IDPad).LinkButtons(TriList); - if (dev is IDvr) - (dev as IDvr).LinkButtons(TriList); - if (dev is INumericKeypad) - (dev as INumericKeypad).LinkButtons(TriList); - if (dev is IPower) - (dev as IPower).LinkButtons(TriList); - if (dev is ITransport) - (dev as ITransport).LinkButtons(TriList); - //if (dev is IRadio) - // (dev as IRadio).LinkButtons(this); // +++++++++++++ Make part of this into page manager - - //if (dev is ICustomFunctions) - //{ - // var custBridge = (dev as ICustomFunctions).GetCustomBridge(); - // custBridge.Link(this.Remote); - } - - /// - /// Detaches the buttons and feedback from the room's current audio device - /// - void ClearAudioDeviceConnections() - { - TriList.ClearBoolSigAction(UIBoolJoin.VolumeUpPress); - TriList.ClearBoolSigAction(UIBoolJoin.VolumeDownPress); - TriList.ClearBoolSigAction(UIBoolJoin.Volume1ProgramMutePressAndFB); - - var fDev = CurrentRoom.CurrentVolumeControls as IBasicVolumeWithFeedback; - if (fDev != null) - { - TriList.ClearUShortSigAction(UIUshortJoin.VolumeSlider1Value); - fDev.VolumeLevelFeedback.UnlinkInputSig( - TriList.UShortInput[UIUshortJoin.VolumeSlider1Value]); - } - } - - /// - /// Attaches the buttons and feedback to the room's current audio device - /// - void RefreshAudioDeviceConnections() - { - var dev = CurrentRoom.CurrentVolumeControls; - if (dev != null) // connect buttons - { - TriList.SetBoolSigAction(UIBoolJoin.VolumeUpPress, VolumeUpPress); - TriList.SetBoolSigAction(UIBoolJoin.VolumeDownPress, VolumeDownPress); - TriList.SetSigFalseAction(UIBoolJoin.Volume1ProgramMutePressAndFB, dev.MuteToggle); - } - - var fbDev = dev as IBasicVolumeWithFeedback; - if (fbDev == null) // this should catch both IBasicVolume and IBasicVolumeWithFeeback - TriList.UShortInput[UIUshortJoin.VolumeSlider1Value].UShortValue = 0; - else - { - // slider - TriList.SetUShortSigAction(UIUshortJoin.VolumeSlider1Value, fbDev.SetVolume); - // feedbacks - fbDev.MuteFeedback.LinkInputSig(TriList.BooleanInput[UIBoolJoin.Volume1ProgramMutePressAndFB]); - fbDev.VolumeLevelFeedback.LinkInputSig( - TriList.UShortInput[UIUshortJoin.VolumeSlider1Value]); - } - } - - /// - /// Handler for when the room's volume control device changes - /// - void CurrentRoom_CurrentAudioDeviceChange(object sender, VolumeDeviceChangeEventArgs args) - { - if (args.Type == ChangeType.WillChange) - ClearAudioDeviceConnections(); - else // did change - RefreshAudioDeviceConnections(); - } - - /// - /// Handles source change - /// - void CurrentRoom_SourceInfoChange(EssentialsRoomBase room, - SourceListItem info, ChangeType change) - { - if (change == ChangeType.WillChange) - DisconnectSource(info); - else - RefreshSourceInfo(); - } - } +using System; +using System.Collections.Generic; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro; +using Crestron.SimplSharpPro.UI; + +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.SmartObjects; +using PepperDash.Essentials.Core.PageManagers; + +namespace PepperDash.Essentials +{ + /// + /// + /// + public class EssentialsHuddlePanelAvFunctionsDriver : PanelDriverBase + { + CrestronTouchpanelPropertiesConfig Config; + + public enum UiDisplayMode + { + PresentationMode, AudioSetup + } + + /// + /// Whether volume ramping from this panel will show the volume + /// gauge popup. + /// + public bool ShowVolumeGauge { get; set; } + + /// + /// The amount of time that the volume buttons stays on screen, in ms + /// + public uint VolumeButtonPopupTimeout + { + get { return VolumeButtonsPopupFeedback.TimeoutMs; } + set { VolumeButtonsPopupFeedback.TimeoutMs = value; } + } + + /// + /// The amount of time that the volume gauge stays on screen, in ms + /// + public uint VolumeGaugePopupTimeout + { + get { return VolumeGaugeFeedback.TimeoutMs; } + set { VolumeGaugeFeedback.TimeoutMs = value; } + } + + /// + /// + /// + public uint PowerOffTimeout { get; set; } + + /// + /// + /// + public string DefaultRoomKey + { + get { return _DefaultRoomKey; } + set + { + _DefaultRoomKey = value; + //CurrentRoom = DeviceManager.GetDeviceForKey(value) as EssentialsHuddleSpaceRoom; + } + } + string _DefaultRoomKey; + + /// + /// + /// + public EssentialsHuddleSpaceRoom CurrentRoom + { + get { return _CurrentRoom; } + set + { + SetCurrentRoom(value); + } + } + EssentialsHuddleSpaceRoom _CurrentRoom; + + /// + /// + /// + //uint CurrentInterlockedModalJoin; + + /// + /// For hitting feedback + /// + BoolInputSig ShareButtonSig; + BoolInputSig EndMeetingButtonSig; + + /// + /// Controls the extended period that the volume gauge shows on-screen, + /// as triggered by Volume up/down operations + /// + BoolFeedbackPulseExtender VolumeGaugeFeedback; + + /// + /// Controls the period that the volume buttons show on non-hard-button + /// interfaces + /// + BoolFeedbackPulseExtender VolumeButtonsPopupFeedback; + + /// + /// The parent driver for this + /// + PanelDriverBase Parent; + + /// + /// All children attached to this driver. For hiding and showing as a group. + /// + List ChildDrivers = new List(); + + List CurrentDisplayModeSigsInUse = new List(); + + //// Important smart objects + + /// + /// Smart Object 3200 + /// + SubpageReferenceList SourcesSrl; + + /// + /// Smart Object 15022 + /// + SubpageReferenceList ActivityFooterSrl; + + /// + /// Tracks which audio page group the UI is in + /// + UiDisplayMode CurrentDisplayMode; + + /// + /// The AV page mangagers that have been used, to keep them alive for later + /// + Dictionary PageManagers = new Dictionary(); + + /// + /// Current page manager running for a source + /// + PageManager CurrentSourcePageManager; + + /// + /// Will auto-timeout a power off + /// + CTimer PowerOffTimer; + + ModalDialog PowerDownModal; + + ModalDialog WarmingCoolingModal; + + JoinedSigInterlock PopupInterlock; + + /// + /// Constructor + /// + public EssentialsHuddlePanelAvFunctionsDriver(PanelDriverBase parent, CrestronTouchpanelPropertiesConfig config) + : base(parent.TriList) + { + Config = config; + Parent = parent; + PopupInterlock = new JoinedSigInterlock(TriList); + + SourcesSrl = new SubpageReferenceList(TriList, 3200, 3, 3, 3); + ActivityFooterSrl = new SubpageReferenceList(TriList, 15022, 3, 3, 3); + ShareButtonSig = ActivityFooterSrl.BoolInputSig(1, 1); + + SetupActivityFooterWhenRoomOff(); + + ShowVolumeGauge = true; + + // One-second pulse extender for volume gauge + VolumeGaugeFeedback = new BoolFeedbackPulseExtender(1500); + VolumeGaugeFeedback.Feedback + .LinkInputSig(TriList.BooleanInput[UIBoolJoin.VolumeGaugePopupVisible]); + + VolumeButtonsPopupFeedback = new BoolFeedbackPulseExtender(4000); + VolumeButtonsPopupFeedback.Feedback + .LinkInputSig(TriList.BooleanInput[UIBoolJoin.VolumeButtonPopupVisible]); + + PowerOffTimeout = 30000; + + TriList.StringInput[UIStringJoin.StartActivityText].StringValue = + "Tap Share to begin"; + } + + /// + /// + /// + public override void Show() + { + TriList.BooleanInput[UIBoolJoin.TopBarVisible].BoolValue = true; + TriList.BooleanInput[UIBoolJoin.ActivityFooterVisible].BoolValue = true; + + // Default to showing rooms/sources now. + ShowMode(UiDisplayMode.PresentationMode); + + // Attach actions + TriList.SetSigFalseAction(UIBoolJoin.VolumeButtonPopupPress, VolumeButtonsTogglePress); + + //Interlocked modals + TriList.SetSigFalseAction(UIBoolJoin.InterlockedModalClosePress, PopupInterlock.HideAndClear);// HideCurrentInterlockedModal); + TriList.SetSigFalseAction(UIBoolJoin.HelpPress, () => + { + string message = null; + var room = DeviceManager.GetDeviceForKey(Config.DefaultRoomKey) + as EssentialsHuddleSpaceRoom; + if (room != null) + message = room.Config.HelpMessage; + else + message = "Sorry, no help message available. No room connected."; + TriList.StringInput[UIStringJoin.HelpMessage].StringValue = message; + PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.HelpPageVisible); // ShowInterlockedModal(UIBoolJoin.HelpPageVisible); + }); + + //TriList.SetSigFalseAction(UIBoolJoin.RoomHeaderButtonPress, () => + // ShowInterlockedModal(UIBoolJoin.RoomHeaderPageVisible)); + + // Setup button + TriList.SetSigHeldAction(UIBoolJoin.GearHeaderButtonPress, 2000, + () => PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.TechPanelSetupVisible));// ShowInterlockedModal(UIBoolJoin.TechPanelSetupVisible)); + TriList.SetSigFalseAction(UIBoolJoin.TechPagesExitButton, () => + PopupInterlock.HideAndClear()); // HideCurrentInterlockedModal()); +#warning This gets overridden by config after NYU demo + if(TriList is CrestronApp) + TriList.BooleanInput[UIBoolJoin.GearButtonVisible].BoolValue = false; + else + TriList.BooleanInput[UIBoolJoin.GearButtonVisible].BoolValue = true; + + // power-related functions + // Note: some of these are not directly-related to the huddle space UI, but are held over + // in case + TriList.SetSigFalseAction(UIBoolJoin.ShowPowerOffPress, PowerButtonPressed); + TriList.SetSigFalseAction(UIBoolJoin.PowerOffMorePress, () => + { + CancelPowerOffTimer(); + TriList.BooleanInput[UIBoolJoin.PowerOffStep1Visible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.PowerOffStep2Visible].BoolValue = true; + }); + TriList.SetSigFalseAction(UIBoolJoin.DisplayPowerTogglePress, () => + { + if (CurrentRoom != null && CurrentRoom.DefaultDisplay is IPower) + (CurrentRoom.DefaultDisplay as IPower).PowerToggle(); + }); + + base.Show(); + } + + /// + /// + /// + public override void Hide() + { + HideAndClearCurrentDisplayModeSigsInUse(); + TriList.BooleanInput[UIBoolJoin.TopBarVisible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.ActivityFooterVisible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.TapToBeginVisible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false; + //TriList.BooleanInput[UIBoolJoin.StagingPageVisible].BoolValue = false; + VolumeButtonsPopupFeedback.ClearNow(); + //CancelPowerOff(); + + base.Hide(); + } + + /// + /// Shows the various "modes" that this driver controls. Presentation, Setup page + /// + /// + public void ShowMode(UiDisplayMode mode) + { + //Clear whatever is showing now. + HideAndClearCurrentDisplayModeSigsInUse(); + CurrentDisplayMode = mode; + switch (mode) + { + case UiDisplayMode.PresentationMode: + // show start page or staging... + if (CurrentRoom.OnFeedback.BoolValue) + { + TriList.BooleanInput[UIBoolJoin.StagingPageVisible].BoolValue = true; + TriList.BooleanInput[UIBoolJoin.TapToBeginVisible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false; + } + else + { + TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = true; + TriList.BooleanInput[UIBoolJoin.TapToBeginVisible].BoolValue = true; + TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false; + } + // Date/time + if (Config.ShowDate && Config.ShowTime) + { + TriList.BooleanInput[UIBoolJoin.DateAndTimeVisible].BoolValue = true; + TriList.BooleanInput[UIBoolJoin.DateOnlyVisible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.TimeOnlyVisible].BoolValue = false; + } + else + { + TriList.BooleanInput[UIBoolJoin.DateAndTimeVisible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.DateOnlyVisible].BoolValue = Config.ShowDate; + TriList.BooleanInput[UIBoolJoin.TimeOnlyVisible].BoolValue = Config.ShowTime; + } + + ShowCurrentDisplayModeSigsInUse(); + break; + } + } + + /// + /// When the room is off, set the footer SRL + /// + void SetupActivityFooterWhenRoomOff() + { + ActivityFooterSrl.Clear(); + ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(1, ActivityFooterSrl, 0, + b => { if (!b) ShareButtonPressed(); })); + ActivityFooterSrl.Count = 1; + TriList.UShortInput[UIUshortJoin.PresentationListCaretMode].UShortValue = 0; + ShareButtonSig.BoolValue = false; + } + + /// + /// Sets up the footer SRL for when the room is on + /// + void SetupActivityFooterWhenRoomOn() + { + ActivityFooterSrl.Clear(); + ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(1, ActivityFooterSrl, + 0, null)); + ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(2, ActivityFooterSrl, + 3, b => { if (!b) PowerButtonPressed(); })); + ActivityFooterSrl.Count = 2; + TriList.UShortInput[UIUshortJoin.PresentationListCaretMode].UShortValue = 1; + EndMeetingButtonSig = ActivityFooterSrl.BoolInputSig(2, 1); + ShareButtonSig.BoolValue = CurrentRoom.OnFeedback.BoolValue; + } + + /// + /// Attached to activity list share button + /// + void ShareButtonPressed() + { + ShareButtonSig.BoolValue = true; + TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.StagingPageVisible].BoolValue = true; + TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = true; + // Run default source when room is off and share is pressed + if (!CurrentRoom.OnFeedback.BoolValue) + CurrentRoom.RunDefaultRoute(); + } + + /// + /// Hides a current modal if showing and then shows a new. + /// + /// + //void ShowInterlockedModal(uint join) + //{ + // if (CurrentInterlockedModalJoin == join) + // HideCurrentInterlockedModal(); + // else + // { + // // sets the sig true if the join is right + // TriList.BooleanInput[UIBoolJoin.HelpPageVisible].BoolValue = join == UIBoolJoin.HelpPageVisible; + // TriList.BooleanInput[UIBoolJoin.RoomHeaderPageVisible].BoolValue = join == UIBoolJoin.RoomHeaderPageVisible; + // TriList.BooleanInput[UIBoolJoin.VolumesPageVisible].BoolValue = join == UIBoolJoin.VolumesPageVisible; + // TriList.BooleanInput[UIBoolJoin.TechPanelSetupVisible].BoolValue = join == UIBoolJoin.TechPanelSetupVisible; + // CurrentInterlockedModalJoin = join; + // } + //} + + ///// + ///// Helper to hide the current interlocked modal + ///// + //void HideCurrentInterlockedModal() + //{ + // TriList.BooleanInput[CurrentInterlockedModalJoin].BoolValue = false; + // CurrentInterlockedModalJoin = 0; + //} + + + /// + /// Shows all sigs that are in CurrentDisplayModeSigsInUse + /// + void ShowCurrentDisplayModeSigsInUse() + { + foreach (var sig in CurrentDisplayModeSigsInUse) + sig.BoolValue = true; + } + + /// + /// Hides all CurrentDisplayModeSigsInUse sigs and clears the array + /// + void HideAndClearCurrentDisplayModeSigsInUse() + { + foreach (var sig in CurrentDisplayModeSigsInUse) + sig.BoolValue = false; + CurrentDisplayModeSigsInUse.Clear(); + } + + /// + /// Send the UI back depending on location, not used in huddle UI + /// + public override void BackButtonPressed() + { + switch (CurrentDisplayMode) + { + case UiDisplayMode.PresentationMode: + //CancelReturnToSourceTimer(); + BackToHome(); + break; + } + } + + /// + /// + /// + void BackToHome() + { + Hide(); + Parent.Show(); + } + + /// + /// Loads the appropriate Sigs into CurrentDisplayModeSigsInUse and shows them + /// + void ShowCurrentSource() + { + if (CurrentRoom.CurrentSourceInfo == null) + return; + + var uiDev = CurrentRoom.CurrentSourceInfo.SourceDevice as IUiDisplayInfo; + PageManager pm = null; + // If we need a page manager, get an appropriate one + if (uiDev != null) + { + TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false; + // Got an existing page manager, get it + if (PageManagers.ContainsKey(uiDev)) + pm = PageManagers[uiDev]; + // Otherwise make an apporiate one + else if (uiDev is ISetTopBoxControls) + //pm = new SetTopBoxMediumPageManager(uiDev as ISetTopBoxControls, TriList); + pm = new SetTopBoxThreePanelPageManager(uiDev as ISetTopBoxControls, TriList); + else if (uiDev is IDiscPlayerControls) + pm = new DiscPlayerMediumPageManager(uiDev as IDiscPlayerControls, TriList); + else + pm = new DefaultPageManager(uiDev, TriList); + PageManagers[uiDev] = pm; + CurrentSourcePageManager = pm; + pm.Show(); + } + } + + /// + /// Called from button presses on source, where We can assume we want + /// to change to the proper screen. + /// + /// The key name of the route to run + void UiSelectSource(string key) + { + // Run the route and when it calls back, show the source + CurrentRoom.RunRouteAction(key, null); + } + + /// + /// + /// + public void PowerButtonPressed() + { + if (!CurrentRoom.OnFeedback.BoolValue + || CurrentRoom.ShutdownPromptTimer.IsRunningFeedback.BoolValue) + return; + + CurrentRoom.StartShutdown(ShutdownType.Manual); + } + + /// + /// + /// + /// + /// + void ShutdownPromptTimer_HasStarted(object sender, EventArgs e) + { + // Do we need to check where the UI is? No? + var timer = CurrentRoom.ShutdownPromptTimer; + EndMeetingButtonSig.BoolValue = true; + ShareButtonSig.BoolValue = false; + + if (CurrentRoom.ShutdownType == ShutdownType.Manual) + { + PowerDownModal = new ModalDialog(TriList); + var message = string.Format("Meeting will end in {0} seconds", CurrentRoom.ShutdownPromptSeconds); + + //// figure out a cleaner way to update gauge + //var gauge = CurrentRoom.ShutdownPromptTimer.PercentFeedback; + //EventHandler gaugeHandler = null; + //gaugeHandler = (o, a) => TriList.UShortInput[ModalDialog.TimerGaugeJoin].UShortValue = + // (ushort)(gauge.UShortValue * 65535 / 100); + //gauge.OutputChange += gaugeHandler; + + // Attach timer things to modal + CurrentRoom.ShutdownPromptTimer.TimeRemainingFeedback.OutputChange += ShutdownPromptTimer_TimeRemainingFeedback_OutputChange; + CurrentRoom.ShutdownPromptTimer.PercentFeedback.OutputChange += ShutdownPromptTimer_PercentFeedback_OutputChange; + + // respond to offs by cancelling dialog + var onFb = CurrentRoom.OnFeedback; + EventHandler offHandler = null; + offHandler = (o, a) => + { + if (!onFb.BoolValue) + { + EndMeetingButtonSig.BoolValue = false; + PowerDownModal.HideDialog(); + onFb.OutputChange -= offHandler; + //gauge.OutputChange -= gaugeHandler; + } + }; + onFb.OutputChange += offHandler; + + PowerDownModal.PresentModalDialog(2, "End Meeting", "Power", message, "Cancel", "End Meeting Now", true, true, + but => + { + if (but != 2) // any button except for End cancels + timer.Cancel(); + else + timer.Finish(); + }); + } + } + + /// + /// + /// + /// + /// + void ShutdownPromptTimer_HasFinished(object sender, EventArgs e) + { + //Debug.Console(2, "*#*UI shutdown prompt finished"); + EndMeetingButtonSig.BoolValue = false; + CurrentRoom.ShutdownPromptTimer.TimeRemainingFeedback.OutputChange -= ShutdownPromptTimer_TimeRemainingFeedback_OutputChange; + CurrentRoom.ShutdownPromptTimer.PercentFeedback.OutputChange -= ShutdownPromptTimer_PercentFeedback_OutputChange; + + } + + /// + /// + /// + /// + /// + void ShutdownPromptTimer_WasCancelled(object sender, EventArgs e) + { + //Debug.Console(2, "*#*UI shutdown prompt cancelled"); + if (PowerDownModal != null) + PowerDownModal.HideDialog(); + EndMeetingButtonSig.BoolValue = false; + ShareButtonSig.BoolValue = CurrentRoom.OnFeedback.BoolValue; + + CurrentRoom.ShutdownPromptTimer.TimeRemainingFeedback.OutputChange += ShutdownPromptTimer_TimeRemainingFeedback_OutputChange; + CurrentRoom.ShutdownPromptTimer.PercentFeedback.OutputChange -= ShutdownPromptTimer_PercentFeedback_OutputChange; + } + + void ShutdownPromptTimer_TimeRemainingFeedback_OutputChange(object sender, EventArgs e) + { + + var message = string.Format("Meeting will end in {0} seconds", (sender as StringFeedback).StringValue); + TriList.StringInput[ModalDialog.MessageTextJoin].StringValue = message; + } + + void ShutdownPromptTimer_PercentFeedback_OutputChange(object sender, EventArgs e) + { + var value = (ushort)((sender as IntFeedback).UShortValue * 65535 / 100); + TriList.UShortInput[ModalDialog.TimerGaugeJoin].UShortValue = value; + } + + /// + /// + /// + void CancelPowerOffTimer() + { + if (PowerOffTimer != null) + { + PowerOffTimer.Stop(); + PowerOffTimer = null; + } + } + + /// + /// + /// + void VolumeButtonsTogglePress() + { + if (VolumeButtonsPopupFeedback.BoolValue) + VolumeButtonsPopupFeedback.ClearNow(); + else + { + // Trigger the popup + VolumeButtonsPopupFeedback.BoolValue = true; + VolumeButtonsPopupFeedback.BoolValue = false; + } + } + + /// + /// + /// + /// + public void VolumeUpPress(bool state) + { + // extend timeouts + if (ShowVolumeGauge) + VolumeGaugeFeedback.BoolValue = state; + VolumeButtonsPopupFeedback.BoolValue = state; + if (CurrentRoom.CurrentVolumeControls != null) + CurrentRoom.CurrentVolumeControls.VolumeUp(state); + } + + /// + /// + /// + /// + public void VolumeDownPress(bool state) + { + // extend timeouts + if (ShowVolumeGauge) + VolumeGaugeFeedback.BoolValue = state; + VolumeButtonsPopupFeedback.BoolValue = state; + if (CurrentRoom.CurrentVolumeControls != null) + CurrentRoom.CurrentVolumeControls.VolumeDown(state); + } + + /// + /// Helper for property setter. Sets the panel to the given room, latching up all functionality + /// + void SetCurrentRoom(EssentialsHuddleSpaceRoom room) + { + if (_CurrentRoom == room) return; + // Disconnect current (probably never called) + if (_CurrentRoom != null) + { + // Disconnect current room + _CurrentRoom.CurrentVolumeDeviceChange -= this.CurrentRoom_CurrentAudioDeviceChange; + ClearAudioDeviceConnections(); + _CurrentRoom.CurrentSingleSourceChange -= this.CurrentRoom_SourceInfoChange; + DisconnectSource(_CurrentRoom.CurrentSourceInfo); + _CurrentRoom.ShutdownPromptTimer.HasStarted -= ShutdownPromptTimer_HasStarted; + _CurrentRoom.ShutdownPromptTimer.HasFinished -= ShutdownPromptTimer_HasFinished; + _CurrentRoom.ShutdownPromptTimer.WasCancelled -= ShutdownPromptTimer_WasCancelled; + + _CurrentRoom.OnFeedback.OutputChange += CurrentRoom_OnFeedback_OutputChange; + _CurrentRoom.IsWarmingUpFeedback.OutputChange -= CurrentRoom_IsWarmingFeedback_OutputChange; + _CurrentRoom.IsCoolingDownFeedback.OutputChange -= IsCoolingDownFeedback_OutputChange; + } + + _CurrentRoom = room; + + if (_CurrentRoom != null) + { + // get the source list config and set up the source list + var config = ConfigReader.ConfigObject.SourceLists; + if (config.ContainsKey(_CurrentRoom.SourceListKey)) + { + var srcList = config[_CurrentRoom.SourceListKey]; + // Setup sources list + uint i = 1; // counter for UI list + foreach (var kvp in srcList) + { + var srcConfig = kvp.Value; + if (!srcConfig.IncludeInSourceList) // Skip sources marked this way + continue; + + var actualSource = DeviceManager.GetDeviceForKey(srcConfig.SourceKey) as Device; + if (actualSource == null) + { + Debug.Console(1, "Cannot assign missing source '{0}' to source UI list", + srcConfig.SourceKey); + continue; + } + var routeKey = kvp.Key; + var item = new SubpageReferenceListSourceItem(i++, SourcesSrl, srcConfig, + b => { if (!b) UiSelectSource(routeKey); }); + SourcesSrl.AddItem(item); // add to the SRL + item.RegisterForSourceChange(_CurrentRoom); + } + SourcesSrl.Count = (ushort)(i - 1); + } + // Name and logo + TriList.StringInput[UIStringJoin.CurrentRoomName].StringValue = _CurrentRoom.Name; + if (_CurrentRoom.LogoUrl == null) + { + TriList.BooleanInput[UIBoolJoin.LogoDefaultVisible].BoolValue = true; + TriList.BooleanInput[UIBoolJoin.LogoUrlVisible].BoolValue = false; + } + else + { + TriList.BooleanInput[UIBoolJoin.LogoDefaultVisible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.LogoUrlVisible].BoolValue = true; + TriList.StringInput[UIStringJoin.LogoUrl].StringValue = _CurrentRoom.LogoUrl; + } + + // Shutdown timer + _CurrentRoom.ShutdownPromptTimer.HasStarted += ShutdownPromptTimer_HasStarted; + _CurrentRoom.ShutdownPromptTimer.HasFinished += ShutdownPromptTimer_HasFinished; + _CurrentRoom.ShutdownPromptTimer.WasCancelled += ShutdownPromptTimer_WasCancelled; + + // Link up all the change events from the room + _CurrentRoom.OnFeedback.OutputChange += CurrentRoom_OnFeedback_OutputChange; + CurrentRoom_SyncOnFeedback(); + _CurrentRoom.IsWarmingUpFeedback.OutputChange += CurrentRoom_IsWarmingFeedback_OutputChange; + _CurrentRoom.IsCoolingDownFeedback.OutputChange += IsCoolingDownFeedback_OutputChange; + + _CurrentRoom.CurrentVolumeDeviceChange += CurrentRoom_CurrentAudioDeviceChange; + RefreshAudioDeviceConnections(); + _CurrentRoom.CurrentSingleSourceChange += CurrentRoom_SourceInfoChange; + RefreshSourceInfo(); + } + else + { + // Clear sigs that need to be + TriList.StringInput[UIStringJoin.CurrentRoomName].StringValue = "Select a room"; + } + } + + /// + /// For room on/off changes + /// + void CurrentRoom_OnFeedback_OutputChange(object sender, EventArgs e) + { + CurrentRoom_SyncOnFeedback(); + } + + void CurrentRoom_SyncOnFeedback() + { + var value = _CurrentRoom.OnFeedback.BoolValue; + //Debug.Console(2, CurrentRoom, "UI: Is on event={0}", value); + TriList.BooleanInput[UIBoolJoin.RoomIsOn].BoolValue = value; + + if (value) //ON + { + SetupActivityFooterWhenRoomOn(); + TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.StagingPageVisible].BoolValue = true; + TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.VolumeSingleMute1Visible].BoolValue = true; + + } + else + { + SetupActivityFooterWhenRoomOff(); + TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = true; + TriList.BooleanInput[UIBoolJoin.VolumeSingleMute1Visible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.StagingPageVisible].BoolValue = false; + } + } + + /// + /// + /// + void CurrentRoom_IsWarmingFeedback_OutputChange(object sender, EventArgs e) + { + var value = CurrentRoom.IsWarmingUpFeedback.BoolValue; + //Debug.Console(2, CurrentRoom, "UI: WARMING event={0}", value); + + if (value) + { + WarmingCoolingModal = new ModalDialog(TriList); + WarmingCoolingModal.PresentModalDialog(0, "Powering Up", "Power", "

Room is powering up

Please wait

", + "", "", false, false, null); + } + else + { + if (WarmingCoolingModal != null) + WarmingCoolingModal.CancelDialog(); + } + } + + + void IsCoolingDownFeedback_OutputChange(object sender, EventArgs e) + { + var value = CurrentRoom.IsCoolingDownFeedback.BoolValue; + //Debug.Console(2, CurrentRoom, "UI: Cooldown event={0}", value); + + if (value) + { + WarmingCoolingModal = new ModalDialog(TriList); + WarmingCoolingModal.PresentModalDialog(0, "Shut Down", "Power", "

Room is shutting down

Please wait

", + "", "", false, false, null); + } + else + { + if (WarmingCoolingModal != null) + WarmingCoolingModal.CancelDialog(); + } + } + + /// + /// Hides source for provided source info + /// + /// + void DisconnectSource(SourceListItem previousInfo) + { + if (previousInfo == null) return; + + // Hide whatever is showing + if (IsVisible) + { + if (CurrentSourcePageManager != null) + { + CurrentSourcePageManager.Hide(); + CurrentSourcePageManager = null; + } + } + + if (previousInfo == null) return; + var previousDev = previousInfo.SourceDevice; + + // device type interfaces + if (previousDev is ISetTopBoxControls) + (previousDev as ISetTopBoxControls).UnlinkButtons(TriList); + // common interfaces + if (previousDev is IChannel) + (previousDev as IChannel).UnlinkButtons(TriList); + if (previousDev is IColor) + (previousDev as IColor).UnlinkButtons(TriList); + if (previousDev is IDPad) + (previousDev as IDPad).UnlinkButtons(TriList); + if (previousDev is IDvr) + (previousDev as IDvr).UnlinkButtons(TriList); + if (previousDev is INumericKeypad) + (previousDev as INumericKeypad).UnlinkButtons(TriList); + if (previousDev is IPower) + (previousDev as IPower).UnlinkButtons(TriList); + if (previousDev is ITransport) + (previousDev as ITransport).UnlinkButtons(TriList); + //if (previousDev is IRadio) + // (previousDev as IRadio).UnlinkButtons(this); + } + + /// + /// Refreshes and shows the room's current source + /// + void RefreshSourceInfo() + { + var routeInfo = CurrentRoom.CurrentSourceInfo; + // This will show off popup too + if (this.IsVisible) + ShowCurrentSource(); + + if (routeInfo == null)// || !CurrentRoom.OnFeedback.BoolValue) + { + // Check for power off and insert "Room is off" + TriList.StringInput[UIStringJoin.CurrentSourceName].StringValue = "Room is off"; + TriList.StringInput[UIStringJoin.CurrentSourceIcon].StringValue = "Power"; + this.Hide(); + Parent.Show(); + return; + } + else if (CurrentRoom.CurrentSourceInfo != null) + { + TriList.StringInput[UIStringJoin.CurrentSourceName].StringValue = routeInfo.PreferredName; + TriList.StringInput[UIStringJoin.CurrentSourceIcon].StringValue = routeInfo.Icon; // defaults to "blank" + } + else + { + TriList.StringInput[UIStringJoin.CurrentSourceName].StringValue = "---"; + TriList.StringInput[UIStringJoin.CurrentSourceIcon].StringValue = "Blank"; + } + + // Connect controls + if (routeInfo.SourceDevice != null) + ConnectControlDeviceMethods(routeInfo.SourceDevice); + } + + /// + /// Attach the source to the buttons and things + /// + void ConnectControlDeviceMethods(Device dev) + { + if(dev is ISetTopBoxControls) + (dev as ISetTopBoxControls).LinkButtons(TriList); + if (dev is IChannel) + (dev as IChannel).LinkButtons(TriList); + if (dev is IColor) + (dev as IColor).LinkButtons(TriList); + if (dev is IDPad) + (dev as IDPad).LinkButtons(TriList); + if (dev is IDvr) + (dev as IDvr).LinkButtons(TriList); + if (dev is INumericKeypad) + (dev as INumericKeypad).LinkButtons(TriList); + if (dev is IPower) + (dev as IPower).LinkButtons(TriList); + if (dev is ITransport) + (dev as ITransport).LinkButtons(TriList); + //if (dev is IRadio) + // (dev as IRadio).LinkButtons(this); // +++++++++++++ Make part of this into page manager + + //if (dev is ICustomFunctions) + //{ + // var custBridge = (dev as ICustomFunctions).GetCustomBridge(); + // custBridge.Link(this.Remote); + } + + /// + /// Detaches the buttons and feedback from the room's current audio device + /// + void ClearAudioDeviceConnections() + { + TriList.ClearBoolSigAction(UIBoolJoin.VolumeUpPress); + TriList.ClearBoolSigAction(UIBoolJoin.VolumeDownPress); + TriList.ClearBoolSigAction(UIBoolJoin.Volume1ProgramMutePressAndFB); + + var fDev = CurrentRoom.CurrentVolumeControls as IBasicVolumeWithFeedback; + if (fDev != null) + { + TriList.ClearUShortSigAction(UIUshortJoin.VolumeSlider1Value); + fDev.VolumeLevelFeedback.UnlinkInputSig( + TriList.UShortInput[UIUshortJoin.VolumeSlider1Value]); + } + } + + /// + /// Attaches the buttons and feedback to the room's current audio device + /// + void RefreshAudioDeviceConnections() + { + var dev = CurrentRoom.CurrentVolumeControls; + if (dev != null) // connect buttons + { + TriList.SetBoolSigAction(UIBoolJoin.VolumeUpPress, VolumeUpPress); + TriList.SetBoolSigAction(UIBoolJoin.VolumeDownPress, VolumeDownPress); + TriList.SetSigFalseAction(UIBoolJoin.Volume1ProgramMutePressAndFB, dev.MuteToggle); + } + + var fbDev = dev as IBasicVolumeWithFeedback; + if (fbDev == null) // this should catch both IBasicVolume and IBasicVolumeWithFeeback + TriList.UShortInput[UIUshortJoin.VolumeSlider1Value].UShortValue = 0; + else + { + // slider + TriList.SetUShortSigAction(UIUshortJoin.VolumeSlider1Value, fbDev.SetVolume); + // feedbacks + fbDev.MuteFeedback.LinkInputSig(TriList.BooleanInput[UIBoolJoin.Volume1ProgramMutePressAndFB]); + fbDev.VolumeLevelFeedback.LinkInputSig( + TriList.UShortInput[UIUshortJoin.VolumeSlider1Value]); + } + } + + /// + /// Handler for when the room's volume control device changes + /// + void CurrentRoom_CurrentAudioDeviceChange(object sender, VolumeDeviceChangeEventArgs args) + { + if (args.Type == ChangeType.WillChange) + ClearAudioDeviceConnections(); + else // did change + RefreshAudioDeviceConnections(); + } + + /// + /// Handles source change + /// + void CurrentRoom_SourceInfoChange(EssentialsRoomBase room, + SourceListItem info, ChangeType change) + { + if (change == ChangeType.WillChange) + DisconnectSource(info); + else + RefreshSourceInfo(); + } + } } \ No newline at end of file diff --git a/Essentials/PepperDashEssentials/UI Drivers/EssentialsPanelMainInterfaceDriver.cs b/Essentials/PepperDashEssentials/UIDrivers/Essentials/EssentialsPanelMainInterfaceDriver.cs similarity index 100% rename from Essentials/PepperDashEssentials/UI Drivers/EssentialsPanelMainInterfaceDriver.cs rename to Essentials/PepperDashEssentials/UIDrivers/Essentials/EssentialsPanelMainInterfaceDriver.cs diff --git a/Essentials/PepperDashEssentials/UI Drivers/EssentialsPresentationPanelAvFunctionsDriver.cs b/Essentials/PepperDashEssentials/UIDrivers/Essentials/EssentialsPresentationPanelAvFunctionsDriver.cs similarity index 100% rename from Essentials/PepperDashEssentials/UI Drivers/EssentialsPresentationPanelAvFunctionsDriver.cs rename to Essentials/PepperDashEssentials/UIDrivers/Essentials/EssentialsPresentationPanelAvFunctionsDriver.cs diff --git a/Essentials/PepperDashEssentials/UIDrivers/JoinedSigInterlock.cs b/Essentials/PepperDashEssentials/UIDrivers/JoinedSigInterlock.cs new file mode 100644 index 00000000..d42b70a5 --- /dev/null +++ b/Essentials/PepperDashEssentials/UIDrivers/JoinedSigInterlock.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro.DeviceSupport; + +namespace PepperDash.Essentials +{ + public class JoinedSigInterlock + { + public uint CurrentJoin { get; private set; } + + BasicTriList TriList; + + public JoinedSigInterlock(BasicTriList triList) + { + TriList = triList; + } + + /// + /// Hides CurrentJoin and shows join + /// + public void ShowInterlocked(uint join) + { + if (CurrentJoin > 0) + TriList.BooleanInput[CurrentJoin].BoolValue = false; + CurrentJoin = join; + TriList.BooleanInput[CurrentJoin].BoolValue = true; + } + + /// + /// + /// + /// + public void ShowInterlockedWithToggle(uint join) + { + if (CurrentJoin == join) + HideAndClear(); + else + { + if (CurrentJoin > 0) + TriList.BooleanInput[CurrentJoin].BoolValue = false; + CurrentJoin = join; + TriList.BooleanInput[CurrentJoin].BoolValue = true; + } + } + /// + /// Hides current join and clears CurrentJoin + /// + public void HideAndClear() + { + Hide(); + CurrentJoin = 0; + } + + /// + /// Hides the current join but does not clear the selected join in case + /// it needs to be reshown + /// + public void Hide() + { + if (CurrentJoin > 0) + TriList.BooleanInput[CurrentJoin].BoolValue = false; + } + + /// + /// If CurrentJoin is set, it restores that join + /// + public void Show() + { + if (CurrentJoin > 0) + TriList.BooleanInput[CurrentJoin].BoolValue = true; + } + + } +} \ No newline at end of file diff --git a/Essentials/PepperDashEssentials/UIDrivers/NYU/NyuHuddleVTCPanelAvFunctionsDriver.cs b/Essentials/PepperDashEssentials/UIDrivers/NYU/NyuHuddleVTCPanelAvFunctionsDriver.cs new file mode 100644 index 00000000..312ddcd1 --- /dev/null +++ b/Essentials/PepperDashEssentials/UIDrivers/NYU/NyuHuddleVTCPanelAvFunctionsDriver.cs @@ -0,0 +1,848 @@ +using System; +using System.Collections.Generic; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro; +using Crestron.SimplSharpPro.UI; + +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.SmartObjects; +using PepperDash.Essentials.Core.PageManagers; + +namespace PepperDash.Essentials +{ + /// + /// + /// + public class NyuHuddleVtcPanelAvFunctionsDriver : PanelDriverBase + { + CrestronTouchpanelPropertiesConfig Config; + + public enum UiDisplayMode + { + PresentationMode, AudioSetup + } + + /// + /// Whether volume ramping from this panel will show the volume + /// gauge popup. + /// + public bool ShowVolumeGauge { get; set; } + + /// + /// + /// + public uint PowerOffTimeout { get; set; } + + /// + /// + /// + public string DefaultRoomKey { get; set; } + //{ + // get { return _DefaultRoomKey; } + // set + // { + // _DefaultRoomKey = value; + // } + //} + //string _DefaultRoomKey; + + /// + /// + /// + public EssentialsHuddleSpaceRoom CurrentRoom + { + get { return _CurrentRoom; } + set + { + SetCurrentRoom(value); + } + } + EssentialsHuddleSpaceRoom _CurrentRoom; + + /// + /// + /// + //uint CurrentInterlockedModalJoin; + + /// + /// For hitting feedback + /// + BoolInputSig CallButtonSig; + BoolInputSig ShareButtonSig; + BoolInputSig EndMeetingButtonSig; + + /// + /// The parent driver for this + /// + PanelDriverBase Parent; + + /// + /// All children attached to this driver. For hiding and showing as a group. + /// + List ChildDrivers = new List(); + + List CurrentDisplayModeSigsInUse = new List(); + + //// Important smart objects + + /// + /// Smart Object 3200 + /// + SubpageReferenceList SourcesSrl; + + /// + /// Smart Object 15022 + /// + SubpageReferenceList ActivityFooterSrl; + + /// + /// Tracks which audio page group the UI is in + /// + UiDisplayMode CurrentDisplayMode; + + /// + /// The AV page mangagers that have been used, to keep them alive for later + /// + Dictionary PageManagers = new Dictionary(); + + /// + /// Current page manager running for a source + /// + PageManager CurrentSourcePageManager; + + /// + /// Will auto-timeout a power off + /// + CTimer PowerOffTimer; + + /// + /// + /// + ModalDialog PowerDownModal; + + /// + /// + /// + ModalDialog WarmingCoolingModal; + + /// + /// Represents + /// + JoinedSigInterlock PopupInterlock; + + /// + /// Constructor + /// + public NyuHuddleVtcPanelAvFunctionsDriver(PanelDriverBase parent, CrestronTouchpanelPropertiesConfig config) + : base(parent.TriList) + { + Config = config; + Parent = parent; + PopupInterlock = new JoinedSigInterlock(TriList); + + SourcesSrl = new SubpageReferenceList(TriList, 3200, 3, 3, 3); + + ActivityFooterSrl = new SubpageReferenceList(TriList, 15022, 3, 3, 3); + CallButtonSig = ActivityFooterSrl.BoolInputSig(1, 1); + ShareButtonSig = ActivityFooterSrl.BoolInputSig(2, 1); + + SetupActivityFooterWhenRoomOff(); + + ShowVolumeGauge = true; + PowerOffTimeout = 30000; + + TriList.StringInput[UIStringJoin.StartActivityText].StringValue = + "Tap Share to begin"; + } + + /// + /// + /// + public override void Show() + { + TriList.SetBool(UIBoolJoin.DateAndTimeVisible, Config.ShowDate && Config.ShowTime); + TriList.SetBool(UIBoolJoin.DateOnlyVisible, Config.ShowDate && !Config.ShowTime); + TriList.SetBool(UIBoolJoin.TimeOnlyVisible, !Config.ShowDate && Config.ShowTime); + TriList.SetBool(UIBoolJoin.TopBarVisible, true); + TriList.SetBool(UIBoolJoin.ActivityFooterVisible, true); + + // Default to showing rooms/sources now. + //ShowMode(UiDisplayMode.PresentationMode); + if (CurrentRoom.OnFeedback.BoolValue) + { + TriList.SetBool(UIBoolJoin.StagingPageVisible, true); + TriList.SetBool(UIBoolJoin.TapToBeginVisible, false); + TriList.SetBool(UIBoolJoin.SelectASourceVisible, false); + } + else + { + TriList.SetBool(UIBoolJoin.StartPageVisible, true); + TriList.SetBool(UIBoolJoin.TapToBeginVisible, true); + TriList.SetBool(UIBoolJoin.SelectASourceVisible, false); + } + ShowCurrentDisplayModeSigsInUse(); + + // *** Header Buttons *** + + // Generic "close" button for these modals + TriList.SetSigFalseAction(UIBoolJoin.InterlockedModalClosePress, PopupInterlock.HideAndClear); + + // Help button + TriList.SetSigFalseAction(UIBoolJoin.HelpPress, () => + { + string message = null; + var room = DeviceManager.GetDeviceForKey(Config.DefaultRoomKey) + as EssentialsHuddleSpaceRoom; + if (room != null) + message = room.Config.HelpMessage; + else + message = "Sorry, no help message available. No room connected."; + TriList.StringInput[UIStringJoin.HelpMessage].StringValue = message; + PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.HelpPageVisible); + }); + + // Lights button + TriList.SetSigFalseAction(UIBoolJoin.LightsHeaderButtonPress, () => + { }); + + // Call header button + TriList.SetSigFalseAction(UIBoolJoin.CallHeaderButtonPress, () => + { }); + + // Room name button + //TriList.SetSigFalseAction(UIBoolJoin.RoomHeaderButtonPress, () => + // ShowInterlockedModal(UIBoolJoin.RoomHeaderPageVisible)); + + // Setup button - shows volumes with default button OR hold for tech page + TriList.SetSigHeldAction(UIBoolJoin.GearHeaderButtonPress, 2000, + () => PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.TechPanelSetupVisible), + () => PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.VolumesPageVisible)); + TriList.SetSigFalseAction(UIBoolJoin.TechPagesExitButton, () => + PopupInterlock.HideAndClear()); + + // Default Volume button + TriList.SetSigFalseAction(UIBoolJoin.VolumeDefaultPress, () => // Set default volume method on room + { }); + + + if (TriList is CrestronApp) + TriList.BooleanInput[UIBoolJoin.GearButtonVisible].BoolValue = false; + else + TriList.BooleanInput[UIBoolJoin.GearButtonVisible].BoolValue = true; + + // power-related functions + // Note: some of these are not directly-related to the huddle space UI, but are held over + // in case + TriList.SetSigFalseAction(UIBoolJoin.ShowPowerOffPress, PowerButtonPressed); + + TriList.SetSigFalseAction(UIBoolJoin.DisplayPowerTogglePress, () => + { + if (CurrentRoom != null && CurrentRoom.DefaultDisplay is IPower) + (CurrentRoom.DefaultDisplay as IPower).PowerToggle(); + }); + + base.Show(); + } + + /// + /// + /// + public override void Hide() + { + HideAndClearCurrentDisplayModeSigsInUse(); + TriList.BooleanInput[UIBoolJoin.TopBarVisible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.ActivityFooterVisible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.TapToBeginVisible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false; + base.Hide(); + } + + /// + /// When the room is off, set the footer SRL + /// + void SetupActivityFooterWhenRoomOff() + { + ActivityFooterSrl.Clear(); + ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(1, ActivityFooterSrl, 1, + b => { if (!b) CallButtonPressed(); })); + ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(2, ActivityFooterSrl, 0, + b => { if (!b) ShareButtonPressed(); })); + ActivityFooterSrl.Count = 2; + TriList.UShortInput[UIUshortJoin.PresentationListCaretMode].UShortValue = 0; + ShareButtonSig.BoolValue = false; + } + + /// + /// Sets up the footer SRL for when the room is on + /// + void SetupActivityFooterWhenRoomOn() + { + ActivityFooterSrl.Clear(); + ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(1, ActivityFooterSrl, + 1, null)); + ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(2, ActivityFooterSrl, + 0, null)); + ActivityFooterSrl.AddItem(new SubpageReferenceListActivityItem(3, ActivityFooterSrl, + 3, b => { if (!b) PowerButtonPressed(); })); + ActivityFooterSrl.Count = 2; + TriList.UShortInput[UIUshortJoin.PresentationListCaretMode].UShortValue = 1; + EndMeetingButtonSig = ActivityFooterSrl.BoolInputSig(3, 1); + + ShareButtonSig.BoolValue = CurrentRoom.OnFeedback.BoolValue; + } + + void CallButtonPressed() + { + CallButtonSig.BoolValue = true; + TriList.SetBool(UIBoolJoin.StartPageVisible, false); + TriList.SetBool(UIBoolJoin.StagingPageVisible, false); + TriList.SetBool(UIBoolJoin.SelectASourceVisible, false); + // Call "page"? Or separate UI driver? + } + + /// + /// Attached to activity list share button + /// + void ShareButtonPressed() + { + ShareButtonSig.BoolValue = true; + TriList.SetBool(UIBoolJoin.StartPageVisible, false); + TriList.SetBool(UIBoolJoin.StagingPageVisible, true); + TriList.SetBool(UIBoolJoin.SelectASourceVisible, true); + // Run default source when room is off and share is pressed + if (!CurrentRoom.OnFeedback.BoolValue) + CurrentRoom.RunDefaultRoute(); + } + + /// + /// Shows all sigs that are in CurrentDisplayModeSigsInUse + /// + void ShowCurrentDisplayModeSigsInUse() + { + foreach (var sig in CurrentDisplayModeSigsInUse) + sig.BoolValue = true; + } + + /// + /// Hides all CurrentDisplayModeSigsInUse sigs and clears the array + /// + void HideAndClearCurrentDisplayModeSigsInUse() + { + foreach (var sig in CurrentDisplayModeSigsInUse) + sig.BoolValue = false; + CurrentDisplayModeSigsInUse.Clear(); + } + + + /// + /// Loads the appropriate Sigs into CurrentDisplayModeSigsInUse and shows them + /// + void ShowCurrentSource() + { + if (CurrentRoom.CurrentSourceInfo == null) + return; + + var uiDev = CurrentRoom.CurrentSourceInfo.SourceDevice as IUiDisplayInfo; + PageManager pm = null; + // If we need a page manager, get an appropriate one + if (uiDev != null) + { + TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false; + // Got an existing page manager, get it + if (PageManagers.ContainsKey(uiDev)) + pm = PageManagers[uiDev]; + // Otherwise make an apporiate one + else if (uiDev is ISetTopBoxControls) + //pm = new SetTopBoxMediumPageManager(uiDev as ISetTopBoxControls, TriList); + pm = new SetTopBoxThreePanelPageManager(uiDev as ISetTopBoxControls, TriList); + else if (uiDev is IDiscPlayerControls) + pm = new DiscPlayerMediumPageManager(uiDev as IDiscPlayerControls, TriList); + else + pm = new DefaultPageManager(uiDev, TriList); + PageManagers[uiDev] = pm; + CurrentSourcePageManager = pm; + pm.Show(); + } + } + + /// + /// Called from button presses on source, where We can assume we want + /// to change to the proper screen. + /// + /// The key name of the route to run + void UiSelectSource(string key) + { + // Run the route and when it calls back, show the source + CurrentRoom.RunRouteAction(key, null); + } + + /// + /// + /// + public void PowerButtonPressed() + { + if (!CurrentRoom.OnFeedback.BoolValue + || CurrentRoom.ShutdownPromptTimer.IsRunningFeedback.BoolValue) + return; + + CurrentRoom.StartShutdown(ShutdownType.Manual); + } + + /// + /// + /// + /// + /// + void ShutdownPromptTimer_HasStarted(object sender, EventArgs e) + { + // Do we need to check where the UI is? No? + var timer = CurrentRoom.ShutdownPromptTimer; + EndMeetingButtonSig.BoolValue = true; + ShareButtonSig.BoolValue = false; + + if (CurrentRoom.ShutdownType == ShutdownType.Manual) + { + PowerDownModal = new ModalDialog(TriList); + var message = string.Format("Meeting will end in {0} seconds", CurrentRoom.ShutdownPromptSeconds); + + // Attach timer things to modal + CurrentRoom.ShutdownPromptTimer.TimeRemainingFeedback.OutputChange += ShutdownPromptTimer_TimeRemainingFeedback_OutputChange; + CurrentRoom.ShutdownPromptTimer.PercentFeedback.OutputChange += ShutdownPromptTimer_PercentFeedback_OutputChange; + + // respond to offs by cancelling dialog + var onFb = CurrentRoom.OnFeedback; + EventHandler offHandler = null; + offHandler = (o, a) => + { + if (!onFb.BoolValue) + { + EndMeetingButtonSig.BoolValue = false; + PowerDownModal.HideDialog(); + onFb.OutputChange -= offHandler; + } + }; + onFb.OutputChange += offHandler; + + PowerDownModal.PresentModalDialog(2, "End Meeting", "Power", message, "Cancel", "End Meeting Now", true, true, + but => + { + if (but != 2) // any button except for End cancels + timer.Cancel(); + else + timer.Finish(); + }); + } + } + + /// + /// + /// + /// + /// + void ShutdownPromptTimer_HasFinished(object sender, EventArgs e) + { + //Debug.Console(2, "*#*UI shutdown prompt finished"); + EndMeetingButtonSig.BoolValue = false; + CurrentRoom.ShutdownPromptTimer.TimeRemainingFeedback.OutputChange -= ShutdownPromptTimer_TimeRemainingFeedback_OutputChange; + CurrentRoom.ShutdownPromptTimer.PercentFeedback.OutputChange -= ShutdownPromptTimer_PercentFeedback_OutputChange; + + } + + /// + /// + /// + /// + /// + void ShutdownPromptTimer_WasCancelled(object sender, EventArgs e) + { + //Debug.Console(2, "*#*UI shutdown prompt cancelled"); + if (PowerDownModal != null) + PowerDownModal.HideDialog(); + EndMeetingButtonSig.BoolValue = false; + ShareButtonSig.BoolValue = CurrentRoom.OnFeedback.BoolValue; + + CurrentRoom.ShutdownPromptTimer.TimeRemainingFeedback.OutputChange += ShutdownPromptTimer_TimeRemainingFeedback_OutputChange; + CurrentRoom.ShutdownPromptTimer.PercentFeedback.OutputChange -= ShutdownPromptTimer_PercentFeedback_OutputChange; + } + + void ShutdownPromptTimer_TimeRemainingFeedback_OutputChange(object sender, EventArgs e) + { + + var message = string.Format("Meeting will end in {0} seconds", (sender as StringFeedback).StringValue); + TriList.StringInput[ModalDialog.MessageTextJoin].StringValue = message; + } + + void ShutdownPromptTimer_PercentFeedback_OutputChange(object sender, EventArgs e) + { + var value = (ushort)((sender as IntFeedback).UShortValue * 65535 / 100); + TriList.UShortInput[ModalDialog.TimerGaugeJoin].UShortValue = value; + } + + /// + /// + /// + void CancelPowerOffTimer() + { + if (PowerOffTimer != null) + { + PowerOffTimer.Stop(); + PowerOffTimer = null; + } + } + + /// + /// + /// + /// + public void VolumeUpPress(bool state) + { + if (CurrentRoom.CurrentVolumeControls != null) + CurrentRoom.CurrentVolumeControls.VolumeUp(state); + } + + /// + /// + /// + /// + public void VolumeDownPress(bool state) + { + if (CurrentRoom.CurrentVolumeControls != null) + CurrentRoom.CurrentVolumeControls.VolumeDown(state); + } + + /// + /// Helper for property setter. Sets the panel to the given room, latching up all functionality + /// + void SetCurrentRoom(EssentialsHuddleSpaceRoom room) + { + if (_CurrentRoom == room) return; + // Disconnect current (probably never called) + if (_CurrentRoom != null) + { + // Disconnect current room + _CurrentRoom.CurrentVolumeDeviceChange -= this.CurrentRoom_CurrentAudioDeviceChange; + ClearAudioDeviceConnections(); + _CurrentRoom.CurrentSingleSourceChange -= this.CurrentRoom_SourceInfoChange; + DisconnectSource(_CurrentRoom.CurrentSourceInfo); + _CurrentRoom.ShutdownPromptTimer.HasStarted -= ShutdownPromptTimer_HasStarted; + _CurrentRoom.ShutdownPromptTimer.HasFinished -= ShutdownPromptTimer_HasFinished; + _CurrentRoom.ShutdownPromptTimer.WasCancelled -= ShutdownPromptTimer_WasCancelled; + + _CurrentRoom.OnFeedback.OutputChange += CurrentRoom_OnFeedback_OutputChange; + _CurrentRoom.IsWarmingUpFeedback.OutputChange -= CurrentRoom_IsWarmingFeedback_OutputChange; + _CurrentRoom.IsCoolingDownFeedback.OutputChange -= IsCoolingDownFeedback_OutputChange; + } + + _CurrentRoom = room; + + if (_CurrentRoom != null) + { + // get the source list config and set up the source list + var config = ConfigReader.ConfigObject.SourceLists; + if (config.ContainsKey(_CurrentRoom.SourceListKey)) + { + var srcList = config[_CurrentRoom.SourceListKey]; + // Setup sources list + uint i = 1; // counter for UI list + foreach (var kvp in srcList) + { + var srcConfig = kvp.Value; + if (!srcConfig.IncludeInSourceList) // Skip sources marked this way + continue; + + var actualSource = DeviceManager.GetDeviceForKey(srcConfig.SourceKey) as Device; + if (actualSource == null) + { + Debug.Console(1, "Cannot assign missing source '{0}' to source UI list", + srcConfig.SourceKey); + continue; + } + var routeKey = kvp.Key; + var item = new SubpageReferenceListSourceItem(i++, SourcesSrl, srcConfig, + b => { if (!b) UiSelectSource(routeKey); }); + SourcesSrl.AddItem(item); // add to the SRL + item.RegisterForSourceChange(_CurrentRoom); + } + SourcesSrl.Count = (ushort)(i - 1); + } + // Name and logo + TriList.StringInput[UIStringJoin.CurrentRoomName].StringValue = _CurrentRoom.Name; + if (_CurrentRoom.LogoUrl == null) + { + TriList.BooleanInput[UIBoolJoin.LogoDefaultVisible].BoolValue = true; + TriList.BooleanInput[UIBoolJoin.LogoUrlVisible].BoolValue = false; + } + else + { + TriList.BooleanInput[UIBoolJoin.LogoDefaultVisible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.LogoUrlVisible].BoolValue = true; + TriList.StringInput[UIStringJoin.LogoUrl].StringValue = _CurrentRoom.LogoUrl; + } + + // Shutdown timer + _CurrentRoom.ShutdownPromptTimer.HasStarted += ShutdownPromptTimer_HasStarted; + _CurrentRoom.ShutdownPromptTimer.HasFinished += ShutdownPromptTimer_HasFinished; + _CurrentRoom.ShutdownPromptTimer.WasCancelled += ShutdownPromptTimer_WasCancelled; + + // Link up all the change events from the room + _CurrentRoom.OnFeedback.OutputChange += CurrentRoom_OnFeedback_OutputChange; + CurrentRoom_SyncOnFeedback(); + _CurrentRoom.IsWarmingUpFeedback.OutputChange += CurrentRoom_IsWarmingFeedback_OutputChange; + _CurrentRoom.IsCoolingDownFeedback.OutputChange += IsCoolingDownFeedback_OutputChange; + + _CurrentRoom.CurrentVolumeDeviceChange += CurrentRoom_CurrentAudioDeviceChange; + RefreshAudioDeviceConnections(); + _CurrentRoom.CurrentSingleSourceChange += CurrentRoom_SourceInfoChange; + RefreshSourceInfo(); + } + else + { + // Clear sigs that need to be + TriList.StringInput[UIStringJoin.CurrentRoomName].StringValue = "Select a room"; + } + } + + /// + /// For room on/off changes + /// + void CurrentRoom_OnFeedback_OutputChange(object sender, EventArgs e) + { + CurrentRoom_SyncOnFeedback(); + } + + void CurrentRoom_SyncOnFeedback() + { + var value = _CurrentRoom.OnFeedback.BoolValue; + //Debug.Console(2, CurrentRoom, "UI: Is on event={0}", value); + TriList.BooleanInput[UIBoolJoin.RoomIsOn].BoolValue = value; + + if (value) //ON + { + SetupActivityFooterWhenRoomOn(); + TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.StagingPageVisible].BoolValue = true; + TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.VolumeSingleMute1Visible].BoolValue = true; + + } + else + { + SetupActivityFooterWhenRoomOff(); + TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = true; + TriList.BooleanInput[UIBoolJoin.VolumeSingleMute1Visible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.StagingPageVisible].BoolValue = false; + } + } + + /// + /// + /// + void CurrentRoom_IsWarmingFeedback_OutputChange(object sender, EventArgs e) + { + var value = CurrentRoom.IsWarmingUpFeedback.BoolValue; + //Debug.Console(2, CurrentRoom, "UI: WARMING event={0}", value); + + if (value) + { + WarmingCoolingModal = new ModalDialog(TriList); + WarmingCoolingModal.PresentModalDialog(0, "Powering Up", "Power", "

Room is powering up

Please wait

", + "", "", false, false, null); + } + else + { + if (WarmingCoolingModal != null) + WarmingCoolingModal.CancelDialog(); + } + } + + + void IsCoolingDownFeedback_OutputChange(object sender, EventArgs e) + { + var value = CurrentRoom.IsCoolingDownFeedback.BoolValue; + //Debug.Console(2, CurrentRoom, "UI: Cooldown event={0}", value); + + if (value) + { + WarmingCoolingModal = new ModalDialog(TriList); + WarmingCoolingModal.PresentModalDialog(0, "Shut Down", "Power", "

Room is shutting down

Please wait

", + "", "", false, false, null); + } + else + { + if (WarmingCoolingModal != null) + WarmingCoolingModal.CancelDialog(); + } + } + + /// + /// Hides source for provided source info + /// + /// + void DisconnectSource(SourceListItem previousInfo) + { + if (previousInfo == null) return; + + // Hide whatever is showing + if (IsVisible) + { + if (CurrentSourcePageManager != null) + { + CurrentSourcePageManager.Hide(); + CurrentSourcePageManager = null; + } + } + + if (previousInfo == null) return; + var previousDev = previousInfo.SourceDevice; + + // device type interfaces + if (previousDev is ISetTopBoxControls) + (previousDev as ISetTopBoxControls).UnlinkButtons(TriList); + // common interfaces + if (previousDev is IChannel) + (previousDev as IChannel).UnlinkButtons(TriList); + if (previousDev is IColor) + (previousDev as IColor).UnlinkButtons(TriList); + if (previousDev is IDPad) + (previousDev as IDPad).UnlinkButtons(TriList); + if (previousDev is IDvr) + (previousDev as IDvr).UnlinkButtons(TriList); + if (previousDev is INumericKeypad) + (previousDev as INumericKeypad).UnlinkButtons(TriList); + if (previousDev is IPower) + (previousDev as IPower).UnlinkButtons(TriList); + if (previousDev is ITransport) + (previousDev as ITransport).UnlinkButtons(TriList); + //if (previousDev is IRadio) + // (previousDev as IRadio).UnlinkButtons(this); + } + + /// + /// Refreshes and shows the room's current source + /// + void RefreshSourceInfo() + { + var routeInfo = CurrentRoom.CurrentSourceInfo; + // This will show off popup too + if (this.IsVisible) + ShowCurrentSource(); + + if (routeInfo == null)// || !CurrentRoom.OnFeedback.BoolValue) + { + // Check for power off and insert "Room is off" + TriList.StringInput[UIStringJoin.CurrentSourceName].StringValue = "Room is off"; + TriList.StringInput[UIStringJoin.CurrentSourceIcon].StringValue = "Power"; + this.Hide(); + Parent.Show(); + return; + } + else if (CurrentRoom.CurrentSourceInfo != null) + { + TriList.StringInput[UIStringJoin.CurrentSourceName].StringValue = routeInfo.PreferredName; + TriList.StringInput[UIStringJoin.CurrentSourceIcon].StringValue = routeInfo.Icon; // defaults to "blank" + } + else + { + TriList.StringInput[UIStringJoin.CurrentSourceName].StringValue = "---"; + TriList.StringInput[UIStringJoin.CurrentSourceIcon].StringValue = "Blank"; + } + + // Connect controls + if (routeInfo.SourceDevice != null) + ConnectControlDeviceMethods(routeInfo.SourceDevice); + } + + /// + /// Attach the source to the buttons and things + /// + void ConnectControlDeviceMethods(Device dev) + { + if (dev is ISetTopBoxControls) + (dev as ISetTopBoxControls).LinkButtons(TriList); + if (dev is IChannel) + (dev as IChannel).LinkButtons(TriList); + if (dev is IColor) + (dev as IColor).LinkButtons(TriList); + if (dev is IDPad) + (dev as IDPad).LinkButtons(TriList); + if (dev is IDvr) + (dev as IDvr).LinkButtons(TriList); + if (dev is INumericKeypad) + (dev as INumericKeypad).LinkButtons(TriList); + if (dev is IPower) + (dev as IPower).LinkButtons(TriList); + if (dev is ITransport) + (dev as ITransport).LinkButtons(TriList); + } + + /// + /// Detaches the buttons and feedback from the room's current audio device + /// + void ClearAudioDeviceConnections() + { + TriList.ClearBoolSigAction(UIBoolJoin.VolumeUpPress); + TriList.ClearBoolSigAction(UIBoolJoin.VolumeDownPress); + TriList.ClearBoolSigAction(UIBoolJoin.Volume1ProgramMutePressAndFB); + + var fDev = CurrentRoom.CurrentVolumeControls as IBasicVolumeWithFeedback; + if (fDev != null) + { + TriList.ClearUShortSigAction(UIUshortJoin.VolumeSlider1Value); + fDev.VolumeLevelFeedback.UnlinkInputSig( + TriList.UShortInput[UIUshortJoin.VolumeSlider1Value]); + } + } + + /// + /// Attaches the buttons and feedback to the room's current audio device + /// + void RefreshAudioDeviceConnections() + { + var dev = CurrentRoom.CurrentVolumeControls; + if (dev != null) // connect buttons + { + TriList.SetBoolSigAction(UIBoolJoin.VolumeUpPress, VolumeUpPress); + TriList.SetBoolSigAction(UIBoolJoin.VolumeDownPress, VolumeDownPress); + TriList.SetSigFalseAction(UIBoolJoin.Volume1ProgramMutePressAndFB, dev.MuteToggle); + } + + var fbDev = dev as IBasicVolumeWithFeedback; + if (fbDev == null) // this should catch both IBasicVolume and IBasicVolumeWithFeeback + TriList.UShortInput[UIUshortJoin.VolumeSlider1Value].UShortValue = 0; + else + { + // slider + TriList.SetUShortSigAction(UIUshortJoin.VolumeSlider1Value, fbDev.SetVolume); + // feedbacks + fbDev.MuteFeedback.LinkInputSig(TriList.BooleanInput[UIBoolJoin.Volume1ProgramMutePressAndFB]); + fbDev.VolumeLevelFeedback.LinkInputSig( + TriList.UShortInput[UIUshortJoin.VolumeSlider1Value]); + } + } + + /// + /// Handler for when the room's volume control device changes + /// + void CurrentRoom_CurrentAudioDeviceChange(object sender, VolumeDeviceChangeEventArgs args) + { + if (args.Type == ChangeType.WillChange) + ClearAudioDeviceConnections(); + else // did change + RefreshAudioDeviceConnections(); + } + + /// + /// Handles source change + /// + void CurrentRoom_SourceInfoChange(EssentialsRoomBase room, + SourceListItem info, ChangeType change) + { + if (change == ChangeType.WillChange) + DisconnectSource(info); + else + RefreshSourceInfo(); + } + } +} diff --git a/Essentials/PepperDashEssentials/UI Drivers/SingleSubpageModalAndBackDriver.cs b/Essentials/PepperDashEssentials/UIDrivers/Page Drivers/SingleSubpageModalAndBackDriver.cs similarity index 100% rename from Essentials/PepperDashEssentials/UI Drivers/SingleSubpageModalAndBackDriver.cs rename to Essentials/PepperDashEssentials/UIDrivers/Page Drivers/SingleSubpageModalAndBackDriver.cs diff --git a/Essentials/PepperDashEssentials/UI Drivers/SingleSubpageModalDriver.cs b/Essentials/PepperDashEssentials/UIDrivers/Page Drivers/SingleSubpageModalDriver.cs similarity index 100% rename from Essentials/PepperDashEssentials/UI Drivers/SingleSubpageModalDriver.cs rename to Essentials/PepperDashEssentials/UIDrivers/Page Drivers/SingleSubpageModalDriver.cs diff --git a/Essentials/PepperDashEssentials/UI Drivers/SmartObjectRoomsList.cs b/Essentials/PepperDashEssentials/UIDrivers/SmartObjectRoomsList.cs similarity index 100% rename from Essentials/PepperDashEssentials/UI Drivers/SmartObjectRoomsList.cs rename to Essentials/PepperDashEssentials/UIDrivers/SmartObjectRoomsList.cs diff --git a/Essentials/PepperDashEssentials/UI Drivers/UIBoolJoin.cs b/Essentials/PepperDashEssentials/UIDrivers/UIBoolJoin.cs similarity index 98% rename from Essentials/PepperDashEssentials/UI Drivers/UIBoolJoin.cs rename to Essentials/PepperDashEssentials/UIDrivers/UIBoolJoin.cs index 8ebaf2ed..9ba4c89c 100644 --- a/Essentials/PepperDashEssentials/UI Drivers/UIBoolJoin.cs +++ b/Essentials/PepperDashEssentials/UIDrivers/UIBoolJoin.cs @@ -34,19 +34,6 @@ namespace PepperDash.Essentials /// 3813 /// public const uint Volume1ProgramMutePressAndFB = 3813; - /// - /// 3871 - /// - public const uint VolumeDualMute1Visible = 3871; - /// - /// 3874 - /// - public const uint Volume1SpeechMutePressAndFB = 3874; - /// - /// 3875 - /// - public const uint Volume1BackerVisibility = 3875; - /// /// 3821 /// @@ -113,6 +100,22 @@ namespace PepperDash.Essentials /// public const uint VolumesPageVisible = 3870; /// + /// 3871 + /// + public const uint VolumeDualMute1Visible = 3871; + /// + /// 3874 + /// + public const uint Volume1SpeechMutePressAndFB = 3874; + /// + /// 3875 + /// + public const uint Volume1BackerVisibility = 3875; + /// + /// 3891 + /// + public const uint VolumeDefaultPress = 3891; + /// /// 3901 /// public const uint TechPagesExitButton = 3901; diff --git a/Essentials/PepperDashEssentials/UI Drivers/UISmartObjectJoin.cs b/Essentials/PepperDashEssentials/UIDrivers/UISmartObjectJoin.cs similarity index 100% rename from Essentials/PepperDashEssentials/UI Drivers/UISmartObjectJoin.cs rename to Essentials/PepperDashEssentials/UIDrivers/UISmartObjectJoin.cs diff --git a/Essentials/PepperDashEssentials/UI Drivers/UIStringlJoin.cs b/Essentials/PepperDashEssentials/UIDrivers/UIStringlJoin.cs similarity index 100% rename from Essentials/PepperDashEssentials/UI Drivers/UIStringlJoin.cs rename to Essentials/PepperDashEssentials/UIDrivers/UIStringlJoin.cs diff --git a/Essentials/PepperDashEssentials/UI Drivers/UIUshortJoin.cs b/Essentials/PepperDashEssentials/UIDrivers/UIUshortJoin.cs similarity index 100% rename from Essentials/PepperDashEssentials/UI Drivers/UIUshortJoin.cs rename to Essentials/PepperDashEssentials/UIDrivers/UIUshortJoin.cs diff --git a/Essentials/PepperDashEssentials/UI Drivers/VolumeAndSourceChangeArgs.cs b/Essentials/PepperDashEssentials/UIDrivers/VolumeAndSourceChangeArgs.cs similarity index 100% rename from Essentials/PepperDashEssentials/UI Drivers/VolumeAndSourceChangeArgs.cs rename to Essentials/PepperDashEssentials/UIDrivers/VolumeAndSourceChangeArgs.cs diff --git a/Essentials/PepperDashEssentials/UI Drivers/enums and base.cs b/Essentials/PepperDashEssentials/UIDrivers/enums and base.cs similarity index 100% rename from Essentials/PepperDashEssentials/UI Drivers/enums and base.cs rename to Essentials/PepperDashEssentials/UIDrivers/enums and base.cs diff --git a/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow.csproj b/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow.csproj new file mode 100644 index 00000000..33405f12 --- /dev/null +++ b/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow.csproj @@ -0,0 +1,98 @@ + + + Release + AnyCPU + 9.0.30729 + 2.0 + {225C9CD0-1AA9-464C-A3A2-2117EE45A87E} + Library + Properties + EssentialsHuddleWorkflow + EssentialsHuddleWorkflow + {0B4745B0-194B-4BB6-8E21-E9057CA92300};{4D628B5B-2FBC-4AA6-8C16-197242AEB884};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + WindowsCE + E2BECB1F-8C8C-41ba-B736-9BE7D946A398 + 5.0 + SmartDeviceProject1 + v3.5 + Windows CE + + + + + .allowedReferenceRelatedFileExtensions + true + full + false + bin\Debug\ + DEBUG;TRACE; + prompt + 4 + 512 + true + true + off + + + .allowedReferenceRelatedFileExtensions + none + true + bin\Release\ + prompt + 4 + 512 + true + true + off + + + + + False + ..\..\Essentials\PepperDashEssentials\bin\PepperDashEssentials.dll + + + False + ..\..\..\pepperdash-simplsharp-core\Pepperdash Core\CLZ Builds\PepperDash_Core.dll + + + False + ..\..\Essentials Core\PepperDashEssentialsBase\bin\PepperDash_Essentials_Core.dll + + + False + ..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpCustomAttributesInterface.dll + False + + + False + ..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpHelperInterface.dll + False + + + False + ..\..\..\..\..\..\..\ProgramData\Crestron\SDK\SimplSharpPro.exe + False + + + + + + + + + + + + + + + + + + + + + rem S# Pro preparation will execute after these operations + + \ No newline at end of file diff --git a/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow/Properties/AssemblyInfo.cs b/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..0c28f7e6 --- /dev/null +++ b/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow/Properties/AssemblyInfo.cs @@ -0,0 +1,8 @@ +using System.Reflection; + +[assembly: AssemblyTitle("EssentialsHuddleWorkflow")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("EssentialsHuddleWorkflow")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyVersion("1.0.0.*")] + diff --git a/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow/Properties/ControlSystem.cfg b/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow/Properties/ControlSystem.cfg new file mode 100644 index 00000000..e69de29b diff --git a/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow/Room/EssentialsHuddleSpaceRoom.cs b/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow/Room/EssentialsHuddleSpaceRoom.cs new file mode 100644 index 00000000..bc6749fe --- /dev/null +++ b/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow/Room/EssentialsHuddleSpaceRoom.cs @@ -0,0 +1,420 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +using PepperDash.Core; +using PepperDash.Essentials; +using PepperDash.Essentials.Core; + +namespace PepperDash.Essentials.EssentialsHuddleWorkflow +{ + public class EssentialsHuddleSpaceRoom : EssentialsRoomBase, IHasCurrentSourceInfoChange + { + public event EventHandler CurrentVolumeDeviceChange; + public event SourceInfoChangeHandler CurrentSingleSourceChange; + + protected override Func OnFeedbackFunc + { + get + { + return () => + { + var disp = DefaultDisplay as DisplayBase; + var val = CurrentSourceInfo != null + && CurrentSourceInfo.Type == eSourceListItemType.Route + && disp != null + && disp.PowerIsOnFeedback.BoolValue; + return val; + }; + } + } + /// + /// + /// + protected override Func IsWarmingFeedbackFunc + { + get + { + return () => + { + var disp = DefaultDisplay as DisplayBase; + if (disp != null) + return disp.IsWarmingUpFeedback.BoolValue; + else + return false; + }; + } + } + /// + /// + /// + protected override Func IsCoolingFeedbackFunc + { + get + { + return () => + { + var disp = DefaultDisplay as DisplayBase; + if (disp != null) + return disp.IsCoolingDownFeedback.BoolValue; + else + return false; + }; + } + } + + public EssentialsRoomPropertiesConfig Config { get; private set; } + + public IRoutingSinkWithSwitching DefaultDisplay { get; private set; } + public IRoutingSinkNoSwitching DefaultAudioDevice { get; private set; } + public IBasicVolumeControls DefaultVolumeControls { get; private set; } + + public bool ExcludeFromGlobalFunctions { get; set; } + + /// + /// The config name of the source list + /// + public string SourceListKey { get; set; } + + public string DefaultSourceItem { get; set; } + + public ushort DefaultVolume { get; set; } + + /// + /// If room is off, enables power on to last source. Default true + /// + public bool EnablePowerOnToLastSource { get; set; } + string LastSourceKey; + + /// + /// + /// + public IBasicVolumeControls CurrentVolumeControls + { + get { return _CurrentAudioDevice; } + set + { + if (value == _CurrentAudioDevice) return; + + var oldDev = _CurrentAudioDevice; + // derigister this room from the device, if it can + if (oldDev is IInUseTracking) + (oldDev as IInUseTracking).InUseTracker.RemoveUser(this, "audio"); + var handler = CurrentVolumeDeviceChange; + if (handler != null) + CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(oldDev, value, ChangeType.WillChange)); + _CurrentAudioDevice = value; + if (handler != null) + CurrentVolumeDeviceChange(this, new VolumeDeviceChangeEventArgs(oldDev, value, ChangeType.DidChange)); + // register this room with new device, if it can + if (_CurrentAudioDevice is IInUseTracking) + (_CurrentAudioDevice as IInUseTracking).InUseTracker.AddUser(this, "audio"); + } + } + IBasicVolumeControls _CurrentAudioDevice; + + /// + /// The SourceListItem last run - containing names and icons + /// + public SourceListItem CurrentSourceInfo + { + get { return _CurrentSourceInfo; } + private set + { + if (value == _CurrentSourceInfo) return; + + var handler = CurrentSingleSourceChange; + // remove from in-use tracker, if so equipped + if(_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking) + (_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.RemoveUser(this, "control"); + + if (handler != null) + handler(this, _CurrentSourceInfo, ChangeType.WillChange); + + _CurrentSourceInfo = value; + + // add to in-use tracking + if (_CurrentSourceInfo != null && _CurrentSourceInfo.SourceDevice is IInUseTracking) + (_CurrentSourceInfo.SourceDevice as IInUseTracking).InUseTracker.AddUser(this, "control"); + if (handler != null) + handler(this, _CurrentSourceInfo, ChangeType.DidChange); + } + } + SourceListItem _CurrentSourceInfo; + + public string CurrentSourceInfoKey { get; private set; } + + /// + /// + /// + /// + /// + public EssentialsHuddleSpaceRoom(string key, string name, IRoutingSinkWithSwitching defaultDisplay, + IRoutingSinkNoSwitching defaultAudio, EssentialsRoomPropertiesConfig config) + : base(key, name) + { + Config = config; + DefaultDisplay = defaultDisplay; + DefaultAudioDevice = defaultAudio; + if (defaultAudio is IBasicVolumeControls) + DefaultVolumeControls = defaultAudio as IBasicVolumeControls; + else if (defaultAudio is IHasVolumeDevice) + DefaultVolumeControls = (defaultAudio as IHasVolumeDevice).VolumeDevice; + CurrentVolumeControls = DefaultVolumeControls; + + var disp = DefaultDisplay as DisplayBase; + if (disp != null) + { + // Link power, warming, cooling to display + disp.PowerIsOnFeedback.OutputChange += (o, a) => + { + if (disp.PowerIsOnFeedback.BoolValue != OnFeedback.BoolValue) + { + if (!disp.PowerIsOnFeedback.BoolValue) + CurrentSourceInfo = null; + OnFeedback.FireUpdate(); + } + }; + + disp.IsWarmingUpFeedback.OutputChange += (o, a) => + { + IsWarmingUpFeedback.FireUpdate(); + if (!IsWarmingUpFeedback.BoolValue) + (DefaultDisplay as IBasicVolumeWithFeedback).SetVolume(DefaultVolume); + }; + disp.IsCoolingDownFeedback.OutputChange += (o, a) => + { + IsCoolingDownFeedback.FireUpdate(); + if (IsCoolingDownFeedback.BoolValue) + (DefaultDisplay as IBasicVolumeWithFeedback).SetVolume(DefaultVolume); + }; + } + + SourceListKey = "default"; + EnablePowerOnToLastSource = true; + } + + + /// + /// + /// + public override void Shutdown() + { + RunRouteAction("roomOff"); + } + + /// + /// Routes the default source item, if any + /// + public void RunDefaultRoute() + { + if (DefaultSourceItem != null) + RunRouteAction(DefaultSourceItem); + } + + /// + /// + /// + /// + public void RunRouteAction(string routeKey) + { + RunRouteAction(routeKey, null); + } + + /// + /// Gets a source from config list SourceListKey and dynamically build and executes the + /// route or commands + /// + /// + public void RunRouteAction(string routeKey, Action successCallback) + { + // Run this on a separate thread + new CTimer(o => + { + Debug.Console(1, this, "Run route action '{0}'", routeKey); + var dict = ConfigReader.ConfigObject.GetSourceListForKey(SourceListKey); + if(dict == null) + { + Debug.Console(1, this, "WARNING: Config source list '{0}' not found", SourceListKey); + return; + } + + // Try to get the list item by it's string key + if (!dict.ContainsKey(routeKey)) + { + Debug.Console(1, this, "WARNING: No item '{0}' found on config list '{1}'", + routeKey, SourceListKey); + return; + } + + var item = dict[routeKey]; + //Debug.Console(2, this, "Action {0} has {1} steps", + // item.SourceKey, item.RouteList.Count); + + // End usage timer on last source + if (!string.IsNullOrEmpty(LastSourceKey)) + { + var lastSource = dict[LastSourceKey].SourceDevice; + + try + { + if (lastSource != null && lastSource is IUsageTracking) + (lastSource as IUsageTracking).UsageTracker.EndDeviceUsage(); + } + catch (Exception e) + { + Debug.Console(1, this, "*#* EXCEPTION in end usage tracking (257):\r{0}", e); + } + } + + // Let's run it + if (routeKey.ToLower() != "roomoff") + { + LastSourceKey = routeKey; + } + else + { + CurrentSourceInfoKey = null; + } + + foreach (var route in item.RouteList) + { + // if there is a $defaultAll on route, run two separate + if (route.DestinationKey.Equals("$defaultAll", StringComparison.OrdinalIgnoreCase)) + { + // Going to assume a single-path route for now + var tempVideo = new SourceRouteListItem + { + DestinationKey = "$defaultDisplay", + SourceKey = route.SourceKey, + Type = eRoutingSignalType.Video + }; + DoRoute(tempVideo); + + //var tempAudio = new SourceRouteListItem + //{ + // DestinationKey = "$defaultAudio", + // SourceKey = route.SourceKey, + // Type = eRoutingSignalType.Audio + //}; + //DoRoute(tempAudio); + //continue; -- not sure why this was here + } + else + DoRoute(route); + } + + // Start usage timer on routed source + if (item.SourceDevice is IUsageTracking) + { + (item.SourceDevice as IUsageTracking).UsageTracker.StartDeviceUsage(); + } + + + // Set volume control on room, using default if non provided + IBasicVolumeControls volDev = null; + // Handle special cases for volume control + if (string.IsNullOrEmpty(item.VolumeControlKey) + || item.VolumeControlKey.Equals("$defaultAudio", StringComparison.OrdinalIgnoreCase)) + volDev = DefaultVolumeControls; + else if (item.VolumeControlKey.Equals("$defaultDisplay", StringComparison.OrdinalIgnoreCase)) + volDev = DefaultDisplay as IBasicVolumeControls; + // Or a specific device, probably rarely used. + else + { + var dev = DeviceManager.GetDeviceForKey(item.VolumeControlKey); + if (dev is IBasicVolumeControls) + volDev = dev as IBasicVolumeControls; + else if (dev is IHasVolumeDevice) + volDev = (dev as IHasVolumeDevice).VolumeDevice; + } + CurrentVolumeControls = volDev; + + // store the name and UI info for routes + if (item.SourceKey == "$off") + { + CurrentSourceInfoKey = routeKey; + CurrentSourceInfo = null; + } + else if (item.SourceKey != null) + { + CurrentSourceInfoKey = routeKey; + CurrentSourceInfo = item; + } + // And finally, set the "control". This will trigger event + //CurrentControlDevice = DeviceManager.GetDeviceForKey(item.SourceKey) as Device; + + OnFeedback.FireUpdate(); + + // report back when done + if (successCallback != null) + successCallback(); + + }, 0); // end of CTimer + } + + /// + /// Will power the room on with the last-used source + /// + public void PowerOnToDefaultOrLastSource() + { + if (!EnablePowerOnToLastSource || LastSourceKey == null) + return; + RunRouteAction(LastSourceKey); + } + + /// + /// + /// + /// + /// + bool DoRoute(SourceRouteListItem route) + { + IRoutingSinkNoSwitching dest = null; + + if (route.DestinationKey.Equals("$defaultaudio", StringComparison.OrdinalIgnoreCase)) + dest = DefaultAudioDevice; + else if (route.DestinationKey.Equals("$defaultDisplay", StringComparison.OrdinalIgnoreCase)) + dest = DefaultDisplay; + else + dest = DeviceManager.GetDeviceForKey(route.DestinationKey) as IRoutingSinkNoSwitching; + + if (dest == null) + { + Debug.Console(1, this, "Cannot route, unknown destination '{0}'", route.DestinationKey); + return false; + } + + if (route.SourceKey.Equals("$off", StringComparison.OrdinalIgnoreCase)) + { + dest.ReleaseRoute(); + if (dest is IPower) + (dest as IPower).PowerOff(); + } + else + { + var source = DeviceManager.GetDeviceForKey(route.SourceKey) as IRoutingOutputs; + if (source == null) + { + Debug.Console(1, this, "Cannot route unknown source '{0}' to {1}", route.SourceKey, route.DestinationKey); + return false; + } + dest.ReleaseAndMakeRoute(source, route.Type); + } + return true; + } + + /// + /// Runs "roomOff" action on all rooms not set to ExcludeFromGlobalFunctions + /// + public static void AllRoomsOff() + { + var allRooms = DeviceManager.AllDevices.Where(d => + d is EssentialsHuddleSpaceRoom && !(d as EssentialsHuddleSpaceRoom).ExcludeFromGlobalFunctions); + foreach (var room in allRooms) + (room as EssentialsHuddleSpaceRoom).RunRouteAction("roomOff"); + } + } +} \ No newline at end of file diff --git a/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow/UI/DualDisplaySourceSRLController.cs b/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow/UI/DualDisplaySourceSRLController.cs new file mode 100644 index 00000000..c91d72f1 --- /dev/null +++ b/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow/UI/DualDisplaySourceSRLController.cs @@ -0,0 +1,28 @@ +//using System; +//using System.Collections.Generic; +//using System.Linq; +//using System.Text; +//using Crestron.SimplSharp; +//using Crestron.SimplSharpPro; +//using Crestron.SimplSharpPro.DeviceSupport; +//using Crestron.SimplSharpPro.UI; + +//using PepperDash.Essentials.Core; + +//namespace PepperDash.Essentials +//{ +// public class DualDisplaySourceSRLController : SubpageReferenceList +// { +// public DualDisplaySourceSRLController(BasicTriListWithSmartObject triList, +// uint smartObjectId, EssentialsPresentationRoom room) +// : base(triList, smartObjectId, 3, 3, 3) +// { +// var srcList = room.s items.Values.ToList().OrderBy(s => s.Order); +// foreach (var item in srcList) +// { +// GetBoolFeedbackSig(index, 1).UserObject = new Action(routeAction); + +// } +// } +// } +//} \ No newline at end of file diff --git a/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow/UI/EssentialsTouchpanelController.cs b/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow/UI/EssentialsTouchpanelController.cs new file mode 100644 index 00000000..8ad6ab1a --- /dev/null +++ b/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow/UI/EssentialsTouchpanelController.cs @@ -0,0 +1,221 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharp.CrestronIO; +using Crestron.SimplSharpPro; +using Crestron.SimplSharpPro.DeviceSupport; +using Crestron.SimplSharpPro.UI; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.PageManagers; + +namespace PepperDash.Essentials +{ + public class EssentialsTouchpanelController : Device + { + public BasicTriListWithSmartObject Panel { get; private set; } + + public PanelDriverBase PanelDriver { get; private set; } + + CTimer BacklightTransitionedOnTimer; + + public EssentialsTouchpanelController(string key, string name, Tswx52ButtonVoiceControl tsw, + string projectName, string sgdPath) + : base(key, name) + { + Panel = tsw; + tsw.LoadSmartObjects(sgdPath); + tsw.SigChange += new Crestron.SimplSharpPro.DeviceSupport.SigEventHandler(Tsw_SigChange); + } + + /// + /// Config constructor + /// + public EssentialsTouchpanelController(string key, string name, string type, CrestronTouchpanelPropertiesConfig props, uint id) + : base(key, name) + { + AddPostActivationAction(() => + { + Debug.Console(0, this, "post-activation linking"); + type = type.ToLower(); + try + { + if (type == "crestronapp") + { + var app = new CrestronApp(id, Global.ControlSystem); + app.ParameterProjectName.Value = props.ProjectName; + Panel = app; + } + else if (type == "tsw560") + Panel = new Tsw560(id, Global.ControlSystem); + else if (type == "tsw752") + Panel = new Tsw752(id, Global.ControlSystem); + else if (type == "tsw1052") + Panel = new Tsw1052(id, Global.ControlSystem); + else + { + Debug.Console(0, this, "WARNING: Cannot create TSW controller with type '{0}'", type); + return; + } + } + catch (Exception e) + { + Debug.Console(0, this, "WARNING: Cannot create TSW base class. Panel will not function: {0}", e.Message); + return; + } + + // Reserved sigs + if (Panel is TswFt5ButtonSystem) + { + var tsw = Panel as TswFt5ButtonSystem; + tsw.ExtenderSystemReservedSigs.Use(); + tsw.ExtenderSystemReservedSigs.DeviceExtenderSigChange + += ExtenderSystemReservedSigs_DeviceExtenderSigChange; + } + + new CTimer(o => + { + var regSuccess = Panel.Register(); + if (regSuccess != eDeviceRegistrationUnRegistrationResponse.Success) + Debug.Console(0, this, "WARNING: Registration failed. Continuing, but panel may not function: {0}", regSuccess); + + // Give up cleanly if SGD is not present. + var sgdName = @"\NVRAM\Program" + InitialParametersClass.ApplicationNumber + + @"\sgd\" + props.SgdFile; + if (!File.Exists(sgdName)) + { + Debug.Console(0, this, "WARNING: Smart object file '{0}' not present. Exiting TSW load", sgdName); + return; + } + + Panel.LoadSmartObjects(sgdName); + Panel.SigChange += Tsw_SigChange; + + var mainDriver = new EssentialsPanelMainInterfaceDriver(Panel, props); + // Then the AV driver + + // spin up different room drivers depending on room type + var room = DeviceManager.GetDeviceForKey(props.DefaultRoomKey); + if (room is EssentialsHuddleSpaceRoom) + { + Debug.Console(0, this, "Adding huddle space driver"); + var avDriver = new EssentialsHuddlePanelAvFunctionsDriver(mainDriver, props); + avDriver.CurrentRoom = room as EssentialsHuddleSpaceRoom; + avDriver.DefaultRoomKey = props.DefaultRoomKey; + mainDriver.AvDriver = avDriver; + LoadAndShowDriver(mainDriver); // This is a little convoluted. + + if (Panel is TswFt5ButtonSystem) + { + var tsw = Panel as TswFt5ButtonSystem; + // Wire up hard keys + tsw.Power.UserObject = new Action(b => { if (!b) avDriver.PowerButtonPressed(); }); + //tsw.Home.UserObject = new Action(b => { if (!b) HomePressed(); }); + tsw.Up.UserObject = new Action(avDriver.VolumeUpPress); + tsw.Down.UserObject = new Action(avDriver.VolumeDownPress); + tsw.ButtonStateChange += new ButtonEventHandler(Tsw_ButtonStateChange); + } + } + else if (room is EssentialsPresentationRoom) + { + Debug.Console(0, this, "Adding presentation room driver"); + var avDriver = new EssentialsPresentationPanelAvFunctionsDriver(mainDriver, props); + avDriver.CurrentRoom = room as EssentialsPresentationRoom; + avDriver.DefaultRoomKey = props.DefaultRoomKey; + mainDriver.AvDriver = avDriver; + LoadAndShowDriver(mainDriver); + + if (Panel is TswFt5ButtonSystem) + { + var tsw = Panel as TswFt5ButtonSystem; + // Wire up hard keys + tsw.Power.UserObject = new Action(b => { if (!b) avDriver.PowerButtonPressed(); }); + //tsw.Home.UserObject = new Action(b => { if (!b) HomePressed(); }); + tsw.Up.UserObject = new Action(avDriver.VolumeUpPress); + tsw.Down.UserObject = new Action(avDriver.VolumeDownPress); + tsw.ButtonStateChange += new ButtonEventHandler(Tsw_ButtonStateChange); + } + } + else + { + Debug.Console(0, this, "ERROR: Cannot load AvFunctionsDriver for room '{0}'", props.DefaultRoomKey); + } + }, 0); + }); + } + + public void LoadAndShowDriver(PanelDriverBase driver) + { + PanelDriver = driver; + driver.Show(); + } + + void HomePressed() + { + if (BacklightTransitionedOnTimer == null) + PanelDriver.BackButtonPressed(); + } + + + void ExtenderSystemReservedSigs_DeviceExtenderSigChange(DeviceExtender currentDeviceExtender, SigEventArgs args) + { + // If the sig is transitioning on, mark it in case it was home button that transitioned it + var blOnSig = (Panel as TswFt5ButtonSystem).ExtenderSystemReservedSigs.BacklightOnFeedback; + if (args.Sig == blOnSig && blOnSig.BoolValue) + { + BacklightTransitionedOnTimer = new CTimer(o => + { + BacklightTransitionedOnTimer = null; + }, 200); + } + } + + public void PulseBool(uint join) + { + var act = Panel.BooleanInput[join].UserObject as Action; + if (act != null) + { + act(true); + act(false); + } + } + + public void SetBoolSig(uint join, bool value) + { + var act = Panel.BooleanInput[join].UserObject as Action; + if (act != null) + act(value); + } + + public void SetIntSig(uint join, ushort value) + { + var act = Panel.BooleanInput[join].UserObject as Action; + if (act != null) + { + act(value); + } + } + + void Tsw_SigChange(object currentDevice, Crestron.SimplSharpPro.SigEventArgs args) + { + if (Debug.Level == 2) + Debug.Console(2, this, "Sig change: {0} {1}={2}", args.Sig.Type, args.Sig.Number, args.Sig.StringValue); + var uo = args.Sig.UserObject; + if (uo is Action) + (uo as Action)(args.Sig.BoolValue); + else if (uo is Action) + (uo as Action)(args.Sig.UShortValue); + else if (uo is Action) + (uo as Action)(args.Sig.StringValue); + } + + void Tsw_ButtonStateChange(GenericBase device, ButtonEventArgs args) + { + var uo = args.Button.UserObject; + if(uo is Action) + (uo as Action)(args.Button.State == eButtonState.Pressed); + } + } +} \ No newline at end of file diff --git a/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow/UI/SubpageReferenceListActivityItem.cs b/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow/UI/SubpageReferenceListActivityItem.cs new file mode 100644 index 00000000..4747a61a --- /dev/null +++ b/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow/UI/SubpageReferenceListActivityItem.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro; +using Crestron.SimplSharpPro.UI; + +using PepperDash.Essentials.Core; + +namespace PepperDash.Essentials +{ + public class SubpageReferenceListActivityItem : SubpageReferenceListItem + { + /// + /// + /// + /// + /// + /// 0=Share, 1=Phone Call, 2=Video Call, 3=End Meeting + /// + public SubpageReferenceListActivityItem(uint index, SubpageReferenceList owner, + ushort buttonMode, Action pressAction) + : base(index, owner) + { + Owner.GetBoolFeedbackSig(Index, 1).UserObject = pressAction; + Owner.UShortInputSig(Index, 1).UShortValue = buttonMode; + } + + /// + /// Called by SRL to release all referenced objects + /// + public override void Clear() + { + Owner.BoolInputSig(Index, 1).UserObject = null; + Owner.UShortInputSig(Index, 1).UShortValue = 0; + } + } +} \ No newline at end of file diff --git a/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow/UI/SubpageReferenceListSourceItem.cs b/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow/UI/SubpageReferenceListSourceItem.cs new file mode 100644 index 00000000..73cc5e71 --- /dev/null +++ b/EssentialsHuddleWorkflow/EssentialsHuddleWorkflow/UI/SubpageReferenceListSourceItem.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharpPro; +using Crestron.SimplSharpPro.UI; + +using PepperDash.Essentials.Core; + +namespace PepperDash.Essentials +{ + public class SubpageReferenceListSourceItem : SubpageReferenceListItem + { + public SourceListItem SourceItem { get; private set; } + + public SubpageReferenceListSourceItem(uint index, SubpageReferenceList owner, + SourceListItem sourceItem, Action routeAction) + : base(index, owner) + { + SourceItem = sourceItem; + owner.GetBoolFeedbackSig(index, 1).UserObject = new Action(routeAction); + owner.StringInputSig(index, 1).StringValue = SourceItem.PreferredName; + } + + public void RegisterForSourceChange(IHasCurrentSourceInfoChange room) + { + room.CurrentSingleSourceChange -= room_CurrentSourceInfoChange; + room.CurrentSingleSourceChange += room_CurrentSourceInfoChange; + } + + void room_CurrentSourceInfoChange(EssentialsRoomBase room, SourceListItem info, ChangeType type) + { + if (type == ChangeType.WillChange && info == SourceItem) + ClearFeedback(); + else if (type == ChangeType.DidChange && info == SourceItem) + SetFeedback(); + } + + /// + /// Called by SRL to release all referenced objects + /// + public override void Clear() + { + Owner.BoolInputSig(Index, 1).UserObject = null; + Owner.StringInputSig(Index, 1).StringValue = ""; + } + + /// + /// Sets the selected feedback on the button + /// + public void SetFeedback() + { + Owner.BoolInputSig(Index, 1).BoolValue = true; + } + + /// + /// Clears the selected feedback on the button + /// + public void ClearFeedback() + { + Owner.BoolInputSig(Index, 1).BoolValue = false; + } + } +} \ No newline at end of file diff --git a/Release Package/PepperDashEssentials.cpz b/Release Package/PepperDashEssentials.cpz index e9daf0be..bbb952c7 100644 Binary files a/Release Package/PepperDashEssentials.cpz and b/Release Package/PepperDashEssentials.cpz differ diff --git a/Release Package/PepperDashEssentials.dll b/Release Package/PepperDashEssentials.dll index c8f15a7c..9f5c7562 100644 Binary files a/Release Package/PepperDashEssentials.dll and b/Release Package/PepperDashEssentials.dll differ