private IEnumerable <StatusReportItem> UpdateLocalViewports(MonitorSetupTemplate template) { _localViewports = new ViewportSetupFile { MonitorLayoutKey = _parent.MonitorLayoutKey }; foreach (ShadowVisual shadow in _parent.Viewports) { string name = shadow.Viewport.ViewportName; if (_localViewports.Viewports.ContainsKey(name)) { yield return(new StatusReportItem { Status = $"The viewport '{name}' exists more than once in this profile. Each viewport must have a unique name.", Recommendation = $"Rename one of the duplicated viewports with name '{name}' in this profile", Severity = StatusReportItem.SeverityCode.Warning, Flags = StatusReportItem.StatusFlags.ConfigurationUpToDate }); continue; } Rect rect = MonitorSetup.VisualToRect(shadow.Visual); rect.Offset(shadow.Monitor.Left, shadow.Monitor.Top); _localViewports.Viewports.Add(name, rect); } // now check against our saved state, which we also have to update ViewportSetupFile saved = _parent.Combined.Load(template.ProfileName); if (null == saved) { yield return(new StatusReportItem { Status = "The viewport data for this profile does not exist", Severity = StatusReportItem.SeverityCode.Error, Recommendation = $"Configure {_parent.Name}" }); } else if (saved.MonitorLayoutKey != _localViewports.MonitorLayoutKey || !saved.Viewports.OrderBy(e => e.Key) .SequenceEqual(_localViewports.Viewports.OrderBy(e => e.Key))) { // monitor layout key and the viewport rectangles in order must be equal yield return(new StatusReportItem { Status = "The viewport data for this profile is out of date", Severity = StatusReportItem.SeverityCode.Error, Recommendation = $"Configure {_parent.Name}" }); } }
/// <summary> /// generate the monitor setup file but do not write it out yet /// </summary> /// <returns></returns> private IEnumerable <StatusReportItem> UpdateMonitorSetup(MonitorSetupTemplate template, bool verbose) { List <FormattableString> lines = CreateHeader(template); foreach (StatusReportItem item in GatherViewports(template)) { yield return(item); } // emit in sorted canonical order so we can compare files later foreach (KeyValuePair <string, Rect> viewport in _allViewports.Viewports.OrderBy(p => p.Key)) { if (TryCreateViewport(lines, viewport, out FormattableString code)) { yield return(new StatusReportItem { Status = $"{template.MonitorSetupFileBaseName}: {code}", Flags = INFORMATIONAL }); } else { yield return(new StatusReportItem { Status = $"viewport '{viewport.Key}' was not included in monitor setup because it is not entirely contained in rendered resolution", Severity = StatusReportItem.SeverityCode.Warning, Recommendation = "adjust the viewport location or the monitor layout", Link = StatusReportItem.ProfileEditor, Flags = StatusReportItem.StatusFlags.ConfigurationUpToDate }); } } // find main and ui view extents Rect mainView = Rect.Empty; Rect uiView = Rect.Empty; foreach (ShadowMonitor monitor in _parent.Monitors) { string monitorDescription = $"Monitor at Windows coordinates ({monitor.Monitor.Left},{monitor.Monitor.Top}) of size {monitor.Monitor.Width}x{monitor.Monitor.Height}"; if (!monitor.Included) { if (verbose) { yield return new StatusReportItem { Status = $"{monitorDescription} is not included in monitor setup", Flags = INFORMATIONAL } } ; continue; } Rect rect = MonitorSetup.VisualToRect(monitor.Monitor); if (monitor.Main) { if (_parent.MonitorLayoutMode == MonitorLayoutMode.TopLeftQuarter) { // special Rect scaled = rect; scaled.Scale(0.5d, 0.5d); mainView.Union(scaled); } else { mainView.Union(rect); } if (verbose) { yield return new StatusReportItem { Status = $"{monitorDescription} is used for main view", Flags = INFORMATIONAL } } ; } if (monitor.UserInterface) { uiView.Union(rect); if (verbose) { yield return new StatusReportItem { Status = $"{monitorDescription} is used to display the DCS user interface", Flags = INFORMATIONAL } } ; } if (monitor.ViewportCount > 0) { string plural = monitor.ViewportCount > 1 ? "s" : ""; if (verbose) { yield return new StatusReportItem { Status = $"{monitorDescription} has {monitor.ViewportCount} viewport{plural} from this profile", Flags = INFORMATIONAL } } ; } } // trim to rendered area in case of partial screens mainView.Intersect(_parent.Rendered); uiView.Intersect(_parent.Rendered); // change to DCS coordinates (0,0 at top left of rect, physical pixels) ConvertToDCS(ref mainView); ConvertToDCS(ref uiView); CreateMainView(lines, mainView); if (verbose) { yield return new StatusReportItem { Status = $"MAIN = {{ x = {mainView.Left}, y = {mainView.Top}, width = {mainView.Width}, height = {mainView.Height} }}", Flags = INFORMATIONAL } } ; // check for separate UI view StatusReportItem uiStatus = CreateUserInterfaceViewIfRequired(lines, mainView, uiView, out string uiViewName); if (verbose) { yield return(uiStatus); } // set up required names for viewports (well-known to DCS) lines.Add($"UIMainView = {uiViewName}"); lines.Add($"GU_MAIN_VIEWPORT = Viewports.Center"); foreach (FormattableString line in lines) { ConfigManager.LogManager.LogDebug(FormattableString.Invariant(line)); } if (template.Combined) { _combinedMonitorSetup = Render(lines); } else { _monitorSetup = Render(lines); } }