From c3bea683fc0fb567fec068b6fe6b636a4540f5de Mon Sep 17 00:00:00 2001 From: Neil Dorin Date: Fri, 31 Aug 2018 18:06:43 -0600 Subject: [PATCH] Added ConfigWriter class. Updated AV Funciton Driver UI classes to show shutdown prompt when room about to shut down for vacancy. --- PepperDashEssentials/Config/ConfigWriter.cs | 67 + PepperDashEssentials/ControlSystem.cs | 2 + .../PepperDashEssentials.csproj | 1 + .../RoomOnToDefaultSourceWhenOccupied.cs | 6 +- .../Room/Types/EssentialsHuddleSpaceRoom.cs | 924 +++---- .../EssentialsHuddlePanelAvFunctionsDriver.cs | 2264 ++++++++--------- essentials-framework | 2 +- 7 files changed, 1667 insertions(+), 1599 deletions(-) create mode 100644 PepperDashEssentials/Config/ConfigWriter.cs diff --git a/PepperDashEssentials/Config/ConfigWriter.cs b/PepperDashEssentials/Config/ConfigWriter.cs new file mode 100644 index 00000000..243bafce --- /dev/null +++ b/PepperDashEssentials/Config/ConfigWriter.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharp.CrestronIO; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Core.Config; + +namespace PepperDash.Essentials +{ + public class ConfigWriter + { + + public static bool WriteConfig() + { + bool success = false; + + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Writing Configuration to file"); + + var fileLock = new CCriticalSection(); + + + var filePath = Global.FilePathPrefix + "LocalConfig" + Global.DirectorySeparator + "configurationFile.json"; + + Debug.Console(0, Debug.ErrorLogLevel.Notice, "Attempting to write config file: '{0}'", filePath); + + var configData = JsonConvert.SerializeObject(ConfigReader.ConfigObject); + + try + { + + if (fileLock.TryEnter()) + { + using (StreamWriter sw = new StreamWriter(filePath)) + { + sw.Write(configData); + sw.Flush(); + } + + success = true; + } + else + { + Debug.Console(0, Debug.ErrorLogLevel.Error, "Unable to enter FileLock"); + success = false; + } + } + catch (Exception e) + { + Debug.Console(0, Debug.ErrorLogLevel.Error, "Error: Config write failed: \r{0}", e); + success = false; + } + finally + { + if (fileLock != null && !fileLock.Disposed) + fileLock.Leave(); + + } + + return success; + } + } +} \ No newline at end of file diff --git a/PepperDashEssentials/ControlSystem.cs b/PepperDashEssentials/ControlSystem.cs index d25711ed..ed07033d 100644 --- a/PepperDashEssentials/ControlSystem.cs +++ b/PepperDashEssentials/ControlSystem.cs @@ -35,6 +35,8 @@ namespace PepperDash.Essentials //CrestronConsole.AddNewConsoleCommand(s => GoWithLoad(), "go", "Loads configuration file", // ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand(S => { ConfigWriter.WriteConfig(); }, "writeconfig", "writes the current config to a file", ConsoleAccessLevelEnum.AccessOperator); + CrestronConsole.AddNewConsoleCommand(s => { foreach (var tl in TieLineCollection.Default) diff --git a/PepperDashEssentials/PepperDashEssentials.csproj b/PepperDashEssentials/PepperDashEssentials.csproj index 8d96ad67..e10ed1eb 100644 --- a/PepperDashEssentials/PepperDashEssentials.csproj +++ b/PepperDashEssentials/PepperDashEssentials.csproj @@ -127,6 +127,7 @@ + diff --git a/PepperDashEssentials/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs b/PepperDashEssentials/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs index 8501215e..e50309c2 100644 --- a/PepperDashEssentials/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs +++ b/PepperDashEssentials/Room/Behaviours/RoomOnToDefaultSourceWhenOccupied.cs @@ -273,8 +273,6 @@ namespace PepperDash.Essentials.Room.Behaviours } } - - void CalculateAndSetAcknowledgeExpirationTimeout(ScheduledEvent schEvent, DateTime time1, DateTime time2) { Debug.Console(1, this, "time1.Hour = {0}", time1.Hour); @@ -421,7 +419,7 @@ namespace PepperDash.Essentials.Room.Behaviours } /// - /// Callback for event that enables feature + /// Callback for event that enables feature. Enables feature if config property is true /// /// /// @@ -437,7 +435,7 @@ namespace PepperDash.Essentials.Room.Behaviours } /// - /// Callback for event that enables feature + /// Callback for event that enables feature. Disables feature /// /// /// diff --git a/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs b/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs index ad3f5f61..15a81527 100644 --- a/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs +++ b/PepperDashEssentials/Room/Types/EssentialsHuddleSpaceRoom.cs @@ -1,468 +1,468 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -using PepperDash.Core; -using PepperDash.Essentials.Core; -using PepperDash.Essentials.Room.Config; - -namespace PepperDash.Essentials -{ - public class EssentialsHuddleSpaceRoom : EssentialsRoomBase, IHasCurrentSourceInfoChange, IRunRouteAction, IRunDefaultPresentRoute - { - 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(); - }; - } - - SourceListKey = "default"; - EnablePowerOnToLastSource = true; - } - - - /// - /// - /// - protected override void EndShutdown() - { - SetDefaultLevels(); - - RunDefaultPresentRoute(); - - CrestronEnvironment.Sleep(1000); - - RunRouteAction("roomOff"); - } - - /// - /// Routes the default source item, if any - /// - public override bool RunDefaultPresentRoute() +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +using PepperDash.Core; +using PepperDash.Essentials.Core; +using PepperDash.Essentials.Room.Config; + +namespace PepperDash.Essentials +{ + public class EssentialsHuddleSpaceRoom : EssentialsRoomBase, IHasCurrentSourceInfoChange, IRunRouteAction, IRunDefaultPresentRoute + { + 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(); + }; + } + + SourceListKey = "default"; + EnablePowerOnToLastSource = true; + } + + + /// + /// + /// + protected override void EndShutdown() + { + SetDefaultLevels(); + + RunDefaultPresentRoute(); + + CrestronEnvironment.Sleep(1000); + + RunRouteAction("roomOff"); + } + + /// + /// Routes the default source item, if any + /// + public override bool RunDefaultPresentRoute() { if (DefaultSourceItem == null) { Debug.Console(0, this, "Unable to run default present route, DefaultSourceItem is null."); return false; - } - - RunRouteAction(DefaultSourceItem); - return true; - } - - /// - /// - /// - /// - 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, 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; - } - - if (volDev != CurrentVolumeControls) - { - // zero the volume on the device we are leaving. - // Set the volume to default on device we are entering - if (ZeroVolumeWhenSwtichingVolumeDevices && CurrentVolumeControls is IBasicVolumeWithFeedback) - { - var vd = CurrentVolumeControls as IBasicVolumeWithFeedback; - SavedVolumeLevels[vd] = (uint)vd.VolumeLevelFeedback.IntValue; - vd.SetVolume(0); - } - CurrentVolumeControls = volDev; - if (ZeroVolumeWhenSwtichingVolumeDevices && CurrentVolumeControls is IBasicVolumeWithFeedback) - { - var vd = CurrentVolumeControls as IBasicVolumeWithFeedback; - ushort vol = (SavedVolumeLevels.ContainsKey(vd) ? (ushort)SavedVolumeLevels[vd] : DefaultVolume); - vd.SetVolume(vol); - } - } - - - - // 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 override void PowerOnToDefaultOrLastSource() - { - if (!EnablePowerOnToLastSource || LastSourceKey == null) - return; - RunRouteAction(LastSourceKey); - } - - /// - /// Does what it says - /// - public override void SetDefaultLevels() - { - Debug.Console(1, this, "Restoring default levels"); - var vc = CurrentVolumeControls as IBasicVolumeWithFeedback; - if (vc != null) - vc.SetVolume(DefaultVolume); - } - - /// - /// - /// - /// - /// - 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; - } - - public override void RoomVacatedForTimeoutPeriod(object o) - { - //Implement this - } - - /// - /// 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"); - } - } + } + + RunRouteAction(DefaultSourceItem); + return true; + } + + /// + /// + /// + /// + 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, 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; + } + + if (volDev != CurrentVolumeControls) + { + // zero the volume on the device we are leaving. + // Set the volume to default on device we are entering + if (ZeroVolumeWhenSwtichingVolumeDevices && CurrentVolumeControls is IBasicVolumeWithFeedback) + { + var vd = CurrentVolumeControls as IBasicVolumeWithFeedback; + SavedVolumeLevels[vd] = (uint)vd.VolumeLevelFeedback.IntValue; + vd.SetVolume(0); + } + CurrentVolumeControls = volDev; + if (ZeroVolumeWhenSwtichingVolumeDevices && CurrentVolumeControls is IBasicVolumeWithFeedback) + { + var vd = CurrentVolumeControls as IBasicVolumeWithFeedback; + ushort vol = (SavedVolumeLevels.ContainsKey(vd) ? (ushort)SavedVolumeLevels[vd] : DefaultVolume); + vd.SetVolume(vol); + } + } + + + + // 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 override void PowerOnToDefaultOrLastSource() + { + if (!EnablePowerOnToLastSource || LastSourceKey == null) + return; + RunRouteAction(LastSourceKey); + } + + /// + /// Does what it says + /// + public override void SetDefaultLevels() + { + Debug.Console(1, this, "Restoring default levels"); + var vc = CurrentVolumeControls as IBasicVolumeWithFeedback; + if (vc != null) + vc.SetVolume(DefaultVolume); + } + + /// + /// + /// + /// + /// + 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; + } + + public override void RoomVacatedForTimeoutPeriod(object o) + { + //Implement this + } + + /// + /// 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/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddlePanelAvFunctionsDriver.cs b/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddlePanelAvFunctionsDriver.cs index dddcb326..523a2912 100644 --- a/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddlePanelAvFunctionsDriver.cs +++ b/PepperDashEssentials/UIDrivers/EssentialsHuddle/EssentialsHuddlePanelAvFunctionsDriver.cs @@ -1,1135 +1,1135 @@ -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, IAVDriver - { - 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; - - /// - /// Indicates that the SetHeaderButtons method has completed successfully - /// - public bool HeaderButtonsAreSetUp { get; private set; } - - /// - /// - /// - 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; - - public JoinedSigInterlock PopupInterlock { get; private set; } - - /// - /// The driver for the tech page. Lazy getter for memory usage - /// - PepperDash.Essentials.UIDrivers.EssentialsHuddleTechPageDriver TechDriver - { - get - { - if (_TechDriver == null) - _TechDriver = new PepperDash.Essentials.UIDrivers.EssentialsHuddleTechPageDriver(TriList, CurrentRoom.Config.Tech); - return _TechDriver; - } - } - PepperDash.Essentials.UIDrivers.EssentialsHuddleTechPageDriver _TechDriver; - - - /// - /// Controls timeout of notification ribbon timer - /// - CTimer RibbonTimer; - - /// - /// 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() - { - if (CurrentRoom == null) - { - Debug.Console(1, "ERROR: AVUIFunctionsDriver, Cannot show. No room assigned"); - return; - } - - var roomConf = CurrentRoom.Config; - - TriList.SetString(UIStringJoin.CurrentRoomName, CurrentRoom.Name); - - if (Config.HeaderStyle.ToLower() == CrestronTouchpanelPropertiesConfig.Habanero) - { - TriList.SetSigFalseAction(UIBoolJoin.HeaderRoomButtonPress, () => - PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.RoomHeaderPageVisible)); - } - else if (Config.HeaderStyle.ToLower() == CrestronTouchpanelPropertiesConfig.Verbose) - { - // room name on join 1, concat phone and sip on join 2, no button method - //var addr = roomConf.Addresses; - //if (addr == null) // protect from missing values by using default empties - // addr = new EssentialsRoomAddressPropertiesConfig(); - //// empty string when either missing, pipe when both showing - //TriList.SetString(UIStringJoin.RoomAddressPipeText, - // (string.IsNullOrEmpty(addr.PhoneNumber.Trim()) - // || string.IsNullOrEmpty(addr.SipAddress.Trim())) ? "" : " | "); - //TriList.SetString(UIStringJoin.RoomPhoneText, addr.PhoneNumber); - //TriList.SetString(UIStringJoin.RoomSipText, addr.SipAddress); - } - - 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.TopBarHabaneroDynamicVisible, true); - TriList.BooleanInput[UIBoolJoin.ActivityFooterVisible].BoolValue = true; - - // Default to showing rooms/sources now. - if (CurrentRoom.OnFeedback.BoolValue) - { - TriList.SetBool(UIBoolJoin.TapToBeginVisible, false); - SetupActivityFooterWhenRoomOn(); - } - else - { - TriList.SetBool(UIBoolJoin.StartPageVisible, true); - TriList.SetBool(UIBoolJoin.TapToBeginVisible, true); - SetupActivityFooterWhenRoomOff(); - } - ShowCurrentDisplayModeSigsInUse(); - - // Attach actions - TriList.SetSigFalseAction(UIBoolJoin.VolumeButtonPopupPress, VolumeButtonsTogglePress); - - // Generic "close" button for popup modals - TriList.SetSigFalseAction(UIBoolJoin.InterlockedModalClosePress, PopupInterlock.HideAndClear); - - // Volume related things - TriList.SetSigFalseAction(UIBoolJoin.VolumeDefaultPress, () => CurrentRoom.SetDefaultLevels()); - TriList.SetString(UIStringJoin.AdvancedVolumeSlider1Text, "Room"); - - //TriList.SetSigFalseAction(UIBoolJoin.RoomHeaderButtonPress, () => - // ShowInterlockedModal(UIBoolJoin.RoomHeaderPageVisible)); - - - //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, EndMeetingPress); - - TriList.SetSigFalseAction(UIBoolJoin.DisplayPowerTogglePress, () => - { - if (CurrentRoom != null && CurrentRoom.DefaultDisplay is IPower) - (CurrentRoom.DefaultDisplay as IPower).PowerToggle(); - }); - - base.Show(); - } - - /// - /// - /// - public void EndMeetingPress() - { - if (!CurrentRoom.OnFeedback.BoolValue - || CurrentRoom.ShutdownPromptTimer.IsRunningFeedback.BoolValue) - return; - - CurrentRoom.StartShutdown(eShutdownType.Manual); - } - - /// - /// Reveals the tech page and puts away anything that's in the way. - /// - public void ShowTech() - { - PopupInterlock.HideAndClear(); - TechDriver.Show(); - } - - /// - /// - /// - void ShowLogo() - { - if (CurrentRoom.LogoUrl == null) - { - TriList.SetBool(UIBoolJoin.LogoDefaultVisible, true); - TriList.SetBool(UIBoolJoin.LogoUrlVisible, false); - } - else - { - TriList.SetBool(UIBoolJoin.LogoDefaultVisible, false); - TriList.SetBool(UIBoolJoin.LogoUrlVisible, true); - TriList.SetString(UIStringJoin.LogoUrl, _CurrentRoom.LogoUrl); - } - } - - /// - /// - /// - void HideLogo() - { - TriList.SetBool(UIBoolJoin.LogoDefaultVisible, false); - TriList.SetBool(UIBoolJoin.LogoUrlVisible, false); - } - - /// - /// - /// - public override void Hide() - { - HideAndClearCurrentDisplayModeSigsInUse(); - TriList.BooleanInput[UIBoolJoin.TopBarHabaneroDynamicVisible].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(); - } - - /// - /// Reveals a message on the notification ribbon until cleared - /// - /// Text to display - /// Time in ms to display. 0 to keep on screen - public void ShowNotificationRibbon(string message, int timeout) - { - TriList.SetString(UIStringJoin.NotificationRibbonText, message); - TriList.SetBool(UIBoolJoin.NotificationRibbonVisible, true); - if (timeout > 0) - { - if (RibbonTimer != null) - RibbonTimer.Stop(); - RibbonTimer = new CTimer(o => - { - TriList.SetBool(UIBoolJoin.NotificationRibbonVisible, false); - RibbonTimer = null; - }, timeout); - } - } - - /// - /// Hides the notification ribbon - /// - public void HideNotificationRibbon() - { - TriList.SetBool(UIBoolJoin.NotificationRibbonVisible, false); - if (RibbonTimer != null) - { - RibbonTimer.Stop(); - RibbonTimer = null; - } - } - - /// - /// 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.SourceStagingBarVisible].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.PresentationStagingCaretMode].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, - 4, b => { if (!b) PowerButtonPressed(); })); - ActivityFooterSrl.Count = 2; - TriList.UShortInput[UIUshortJoin.PresentationStagingCaretMode].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.SourceStagingBarVisible].BoolValue = true; - TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = true; - // Run default source when room is off and share is pressed - if (!CurrentRoom.OnFeedback.BoolValue) - CurrentRoom.RunDefaultPresentRoute(); - } - - - /// - /// 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(eShutdownType.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; +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, IAVDriver + { + 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; + + /// + /// Indicates that the SetHeaderButtons method has completed successfully + /// + public bool HeaderButtonsAreSetUp { get; private set; } + + /// + /// + /// + 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; + + public JoinedSigInterlock PopupInterlock { get; private set; } + + /// + /// The driver for the tech page. Lazy getter for memory usage + /// + PepperDash.Essentials.UIDrivers.EssentialsHuddleTechPageDriver TechDriver + { + get + { + if (_TechDriver == null) + _TechDriver = new PepperDash.Essentials.UIDrivers.EssentialsHuddleTechPageDriver(TriList, CurrentRoom.Config.Tech); + return _TechDriver; + } + } + PepperDash.Essentials.UIDrivers.EssentialsHuddleTechPageDriver _TechDriver; + + + /// + /// Controls timeout of notification ribbon timer + /// + CTimer RibbonTimer; + + /// + /// 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() + { + if (CurrentRoom == null) + { + Debug.Console(1, "ERROR: AVUIFunctionsDriver, Cannot show. No room assigned"); + return; + } + + var roomConf = CurrentRoom.Config; + + TriList.SetString(UIStringJoin.CurrentRoomName, CurrentRoom.Name); + + if (Config.HeaderStyle.ToLower() == CrestronTouchpanelPropertiesConfig.Habanero) + { + TriList.SetSigFalseAction(UIBoolJoin.HeaderRoomButtonPress, () => + PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.RoomHeaderPageVisible)); + } + else if (Config.HeaderStyle.ToLower() == CrestronTouchpanelPropertiesConfig.Verbose) + { + // room name on join 1, concat phone and sip on join 2, no button method + //var addr = roomConf.Addresses; + //if (addr == null) // protect from missing values by using default empties + // addr = new EssentialsRoomAddressPropertiesConfig(); + //// empty string when either missing, pipe when both showing + //TriList.SetString(UIStringJoin.RoomAddressPipeText, + // (string.IsNullOrEmpty(addr.PhoneNumber.Trim()) + // || string.IsNullOrEmpty(addr.SipAddress.Trim())) ? "" : " | "); + //TriList.SetString(UIStringJoin.RoomPhoneText, addr.PhoneNumber); + //TriList.SetString(UIStringJoin.RoomSipText, addr.SipAddress); + } + + 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.TopBarHabaneroDynamicVisible, true); + TriList.BooleanInput[UIBoolJoin.ActivityFooterVisible].BoolValue = true; + + // Default to showing rooms/sources now. + if (CurrentRoom.OnFeedback.BoolValue) + { + TriList.SetBool(UIBoolJoin.TapToBeginVisible, false); + SetupActivityFooterWhenRoomOn(); + } + else + { + TriList.SetBool(UIBoolJoin.StartPageVisible, true); + TriList.SetBool(UIBoolJoin.TapToBeginVisible, true); + SetupActivityFooterWhenRoomOff(); + } + ShowCurrentDisplayModeSigsInUse(); + + // Attach actions + TriList.SetSigFalseAction(UIBoolJoin.VolumeButtonPopupPress, VolumeButtonsTogglePress); + + // Generic "close" button for popup modals + TriList.SetSigFalseAction(UIBoolJoin.InterlockedModalClosePress, PopupInterlock.HideAndClear); + + // Volume related things + TriList.SetSigFalseAction(UIBoolJoin.VolumeDefaultPress, () => CurrentRoom.SetDefaultLevels()); + TriList.SetString(UIStringJoin.AdvancedVolumeSlider1Text, "Room"); + + //TriList.SetSigFalseAction(UIBoolJoin.RoomHeaderButtonPress, () => + // ShowInterlockedModal(UIBoolJoin.RoomHeaderPageVisible)); + + + //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, EndMeetingPress); + + TriList.SetSigFalseAction(UIBoolJoin.DisplayPowerTogglePress, () => + { + if (CurrentRoom != null && CurrentRoom.DefaultDisplay is IPower) + (CurrentRoom.DefaultDisplay as IPower).PowerToggle(); + }); + + base.Show(); + } + + /// + /// + /// + public void EndMeetingPress() + { + if (!CurrentRoom.OnFeedback.BoolValue + || CurrentRoom.ShutdownPromptTimer.IsRunningFeedback.BoolValue) + return; + + CurrentRoom.StartShutdown(eShutdownType.Manual); + } + + /// + /// Reveals the tech page and puts away anything that's in the way. + /// + public void ShowTech() + { + PopupInterlock.HideAndClear(); + TechDriver.Show(); + } + + /// + /// + /// + void ShowLogo() + { + if (CurrentRoom.LogoUrl == null) + { + TriList.SetBool(UIBoolJoin.LogoDefaultVisible, true); + TriList.SetBool(UIBoolJoin.LogoUrlVisible, false); + } + else + { + TriList.SetBool(UIBoolJoin.LogoDefaultVisible, false); + TriList.SetBool(UIBoolJoin.LogoUrlVisible, true); + TriList.SetString(UIStringJoin.LogoUrl, _CurrentRoom.LogoUrl); + } + } + + /// + /// + /// + void HideLogo() + { + TriList.SetBool(UIBoolJoin.LogoDefaultVisible, false); + TriList.SetBool(UIBoolJoin.LogoUrlVisible, false); + } + + /// + /// + /// + public override void Hide() + { + HideAndClearCurrentDisplayModeSigsInUse(); + TriList.BooleanInput[UIBoolJoin.TopBarHabaneroDynamicVisible].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(); + } + + /// + /// Reveals a message on the notification ribbon until cleared + /// + /// Text to display + /// Time in ms to display. 0 to keep on screen + public void ShowNotificationRibbon(string message, int timeout) + { + TriList.SetString(UIStringJoin.NotificationRibbonText, message); + TriList.SetBool(UIBoolJoin.NotificationRibbonVisible, true); + if (timeout > 0) + { + if (RibbonTimer != null) + RibbonTimer.Stop(); + RibbonTimer = new CTimer(o => + { + TriList.SetBool(UIBoolJoin.NotificationRibbonVisible, false); + RibbonTimer = null; + }, timeout); + } + } + + /// + /// Hides the notification ribbon + /// + public void HideNotificationRibbon() + { + TriList.SetBool(UIBoolJoin.NotificationRibbonVisible, false); + if (RibbonTimer != null) + { + RibbonTimer.Stop(); + RibbonTimer = null; + } + } + + /// + /// 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.SourceStagingBarVisible].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.PresentationStagingCaretMode].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, + 4, b => { if (!b) PowerButtonPressed(); })); + ActivityFooterSrl.Count = 2; + TriList.UShortInput[UIUshortJoin.PresentationStagingCaretMode].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.SourceStagingBarVisible].BoolValue = true; + TriList.BooleanInput[UIBoolJoin.SelectASourceVisible].BoolValue = true; + // Run default source when room is off and share is pressed + if (!CurrentRoom.OnFeedback.BoolValue) + CurrentRoom.RunDefaultPresentRoute(); + } + + + /// + /// 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(eShutdownType.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 == eShutdownType.Manual || CurrentRoom.ShutdownType == eShutdownType.Vacancy) - { - 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; - //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) - { - EndMeetingButtonSig.BoolValue = false; - CurrentRoom.ShutdownPromptTimer.TimeRemainingFeedback.OutputChange -= ShutdownPromptTimer_TimeRemainingFeedback_OutputChange; - CurrentRoom.ShutdownPromptTimer.PercentFeedback.OutputChange -= ShutdownPromptTimer_PercentFeedback_OutputChange; - } - - /// - /// - /// - /// - /// - void ShutdownPromptTimer_WasCancelled(object sender, EventArgs e) - { - 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(); - - (Parent as EssentialsPanelMainInterfaceDriver).HeaderDriver.SetupHeaderButtons(this, CurrentRoom); - } - else - { - // Clear sigs that need to be - TriList.StringInput[UIStringJoin.CurrentRoomName].StringValue = "Select a room"; - } - } - - //void SetupHeaderButtons() - //{ - // HeaderButtonsAreSetUp = false; - - // TriList.SetBool(UIBoolJoin.TopBarHabaneroDynamicVisible, true); - - // var roomConf = CurrentRoom.Config; - - // // Gear - // TriList.SetString(UIStringJoin.HeaderButtonIcon5, "Gear"); - // TriList.SetSigHeldAction(UIBoolJoin.HeaderIcon5Press, 2000, - // ShowTech, - // null, - // () => - // { - // if (CurrentRoom.OnFeedback.BoolValue) - // PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.VolumesPageVisible); - // else - // PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.VolumesPagePowerOffVisible); - // }); - // TriList.SetSigFalseAction(UIBoolJoin.TechExitButton, () => - // PopupInterlock.HideAndClear()); - - // // Help button and popup - // if (CurrentRoom.Config.Help != null) - // { - // TriList.SetString(UIStringJoin.HelpMessage, roomConf.Help.Message); - // TriList.SetBool(UIBoolJoin.HelpPageShowCallButtonVisible, roomConf.Help.ShowCallButton); - // TriList.SetString(UIStringJoin.HelpPageCallButtonText, roomConf.Help.CallButtonText); - // if (roomConf.Help.ShowCallButton) - // TriList.SetSigFalseAction(UIBoolJoin.HelpPageShowCallButtonPress, () => { }); // ************ FILL IN - // else - // TriList.ClearBoolSigAction(UIBoolJoin.HelpPageShowCallButtonPress); - // } - // else // older config - // { - // TriList.SetString(UIStringJoin.HelpMessage, CurrentRoom.Config.HelpMessage); - // TriList.SetBool(UIBoolJoin.HelpPageShowCallButtonVisible, false); - // TriList.SetString(UIStringJoin.HelpPageCallButtonText, null); - // TriList.ClearBoolSigAction(UIBoolJoin.HelpPageShowCallButtonPress); - // } - // TriList.SetString(UIStringJoin.HeaderButtonIcon4, "Help"); - // TriList.SetSigFalseAction(UIBoolJoin.HeaderIcon4Press, () => - // { - // 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); - // }); - // uint nextJoin = 3953; - - // //// Calendar button - // //if (_CurrentRoom.ScheduleSource != null) - // //{ - // // TriList.SetString(nextJoin, "Calendar"); - // // TriList.SetSigFalseAction(nextJoin, CalendarPress); - - // // nextJoin--; - // //} - - // //nextJoin--; - - // // blank any that remain - // for (var i = nextJoin; i > 3950; i--) - // { - // TriList.SetString(i, "Blank"); - // TriList.SetSigFalseAction(i, () => { }); - // } - - // HeaderButtonsAreSetUp = true; - //} - - - /// - /// 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.SourceStagingBarVisible].BoolValue = true; - TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = false; - TriList.BooleanInput[UIBoolJoin.VolumeSingleMute1Visible].BoolValue = true; - - } - else - { - SetupActivityFooterWhenRoomOff(); - ShowLogo(); - TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = true; - TriList.BooleanInput[UIBoolJoin.VolumeSingleMute1Visible].BoolValue = false; - TriList.BooleanInput[UIBoolJoin.SourceStagingBarVisible].BoolValue = false; - } - } - - /// - /// - /// - void CurrentRoom_IsWarmingFeedback_OutputChange(object sender, EventArgs e) - { - if (CurrentRoom.IsWarmingUpFeedback.BoolValue) - { - ShowNotificationRibbon("Room is powering on. Please wait...", 0); - } - else - { - ShowNotificationRibbon("Room is powered on. Welcome.", 2000); - } - } - - - void IsCoolingDownFeedback_OutputChange(object sender, EventArgs e) - { - if (CurrentRoom.IsCoolingDownFeedback.BoolValue) - { - ShowNotificationRibbon("Room is powering off. Please wait.", 0); - } - else - { - HideNotificationRibbon(); - } - } - - /// - /// 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(); - } - } + if (CurrentRoom.ShutdownType == eShutdownType.Manual || CurrentRoom.ShutdownType == eShutdownType.Vacancy) + { + 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; + //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) + { + EndMeetingButtonSig.BoolValue = false; + CurrentRoom.ShutdownPromptTimer.TimeRemainingFeedback.OutputChange -= ShutdownPromptTimer_TimeRemainingFeedback_OutputChange; + CurrentRoom.ShutdownPromptTimer.PercentFeedback.OutputChange -= ShutdownPromptTimer_PercentFeedback_OutputChange; + } + + /// + /// + /// + /// + /// + void ShutdownPromptTimer_WasCancelled(object sender, EventArgs e) + { + 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(); + + (Parent as EssentialsPanelMainInterfaceDriver).HeaderDriver.SetupHeaderButtons(this, CurrentRoom); + } + else + { + // Clear sigs that need to be + TriList.StringInput[UIStringJoin.CurrentRoomName].StringValue = "Select a room"; + } + } + + //void SetupHeaderButtons() + //{ + // HeaderButtonsAreSetUp = false; + + // TriList.SetBool(UIBoolJoin.TopBarHabaneroDynamicVisible, true); + + // var roomConf = CurrentRoom.Config; + + // // Gear + // TriList.SetString(UIStringJoin.HeaderButtonIcon5, "Gear"); + // TriList.SetSigHeldAction(UIBoolJoin.HeaderIcon5Press, 2000, + // ShowTech, + // null, + // () => + // { + // if (CurrentRoom.OnFeedback.BoolValue) + // PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.VolumesPageVisible); + // else + // PopupInterlock.ShowInterlockedWithToggle(UIBoolJoin.VolumesPagePowerOffVisible); + // }); + // TriList.SetSigFalseAction(UIBoolJoin.TechExitButton, () => + // PopupInterlock.HideAndClear()); + + // // Help button and popup + // if (CurrentRoom.Config.Help != null) + // { + // TriList.SetString(UIStringJoin.HelpMessage, roomConf.Help.Message); + // TriList.SetBool(UIBoolJoin.HelpPageShowCallButtonVisible, roomConf.Help.ShowCallButton); + // TriList.SetString(UIStringJoin.HelpPageCallButtonText, roomConf.Help.CallButtonText); + // if (roomConf.Help.ShowCallButton) + // TriList.SetSigFalseAction(UIBoolJoin.HelpPageShowCallButtonPress, () => { }); // ************ FILL IN + // else + // TriList.ClearBoolSigAction(UIBoolJoin.HelpPageShowCallButtonPress); + // } + // else // older config + // { + // TriList.SetString(UIStringJoin.HelpMessage, CurrentRoom.Config.HelpMessage); + // TriList.SetBool(UIBoolJoin.HelpPageShowCallButtonVisible, false); + // TriList.SetString(UIStringJoin.HelpPageCallButtonText, null); + // TriList.ClearBoolSigAction(UIBoolJoin.HelpPageShowCallButtonPress); + // } + // TriList.SetString(UIStringJoin.HeaderButtonIcon4, "Help"); + // TriList.SetSigFalseAction(UIBoolJoin.HeaderIcon4Press, () => + // { + // 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); + // }); + // uint nextJoin = 3953; + + // //// Calendar button + // //if (_CurrentRoom.ScheduleSource != null) + // //{ + // // TriList.SetString(nextJoin, "Calendar"); + // // TriList.SetSigFalseAction(nextJoin, CalendarPress); + + // // nextJoin--; + // //} + + // //nextJoin--; + + // // blank any that remain + // for (var i = nextJoin; i > 3950; i--) + // { + // TriList.SetString(i, "Blank"); + // TriList.SetSigFalseAction(i, () => { }); + // } + + // HeaderButtonsAreSetUp = true; + //} + + + /// + /// 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.SourceStagingBarVisible].BoolValue = true; + TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.VolumeSingleMute1Visible].BoolValue = true; + + } + else + { + SetupActivityFooterWhenRoomOff(); + ShowLogo(); + TriList.BooleanInput[UIBoolJoin.StartPageVisible].BoolValue = true; + TriList.BooleanInput[UIBoolJoin.VolumeSingleMute1Visible].BoolValue = false; + TriList.BooleanInput[UIBoolJoin.SourceStagingBarVisible].BoolValue = false; + } + } + + /// + /// + /// + void CurrentRoom_IsWarmingFeedback_OutputChange(object sender, EventArgs e) + { + if (CurrentRoom.IsWarmingUpFeedback.BoolValue) + { + ShowNotificationRibbon("Room is powering on. Please wait...", 0); + } + else + { + ShowNotificationRibbon("Room is powered on. Welcome.", 2000); + } + } + + + void IsCoolingDownFeedback_OutputChange(object sender, EventArgs e) + { + if (CurrentRoom.IsCoolingDownFeedback.BoolValue) + { + ShowNotificationRibbon("Room is powering off. Please wait.", 0); + } + else + { + HideNotificationRibbon(); + } + } + + /// + /// 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-framework b/essentials-framework index 5c220272..bf9115f1 160000 --- a/essentials-framework +++ b/essentials-framework @@ -1 +1 @@ -Subproject commit 5c2202723fd8d3d5b5a3d17e600c47f0e10b61c2 +Subproject commit bf9115f17b481c8a1a65128ba02c6da90523ac17