Forge
csharpdeeb25a2
1using Avalonia.Controls;
2using Avalonia.Platform;
3
4namespace CascadeIDE.Services.Presentation;
5
6/// <summary>
7/// Плейсмент <c>(xP+yM)(F)</c> / <c>(F)(xP+yM)</c> на физических дисплеях при ≥2 мониторах (ADR 0017).
8/// Лобовое (<c>F</c>) — на <see cref="Screens.Primary"/>; сплит <c>P+M</c> — по соседству с primary:
9/// если в строке сначала <c>P+M</c>, то на экран слева от primary; если сначала <c>F</c> — на экран справа.
10/// Так строковый порядок остаётся симметричным, а при трёх мониторах не происходит наложения на один дисплей
11/// из-за того, что главное окно по умолчанию открывается на primary, а не на «первом» в LTR.
12/// </summary>
13public static class PresentationPmPlusForwardPlacement
14{
15 /// <summary>
16 /// Индексы в массиве <see cref="PresentationMonitorTopology.OrderScreensForPresentation"/> для главного (F) и окна P+M.
17 /// </summary>
18 public static bool TryGetOrderedIndices(
19 Screens screens,
20 IReadOnlyList<IReadOnlyList<PresentationAnchorSlot>> parseScreens,
21 out int forwardOrderedIndex,
22 out int pmOrderedIndex)
23 {
24 forwardOrderedIndex = 0;
25 pmOrderedIndex = 0;
26
27 if (!PresentationLayoutAnalyzer.IsPmPlusForwardTwoScreenPreset(parseScreens))
28 return false;
29
30 if (screens.All.Count < 2)
31 return false;
32
33 if (!PresentationLayoutAnalyzer.TryGetMainWindowPresentationScreenIndex(parseScreens, out var forwardGroupIdx))
34 return false;
35
36 var ordered = PresentationMonitorTopology.OrderScreensForPresentation(screens.All);
37 var pIdx = FindPrimaryOrderedIndex(ordered, screens.Primary);
38
39 // forwardGroupIdx == 0 → в строке сначала F, затем P+M.
40 var pmGroupBeforeForward = forwardGroupIdx == 1;
41
42 ComputeForwardAndPmOrderedIndices(ordered.Count, pIdx, pmGroupBeforeForward, out forwardOrderedIndex, out pmOrderedIndex);
43 return true;
44 }
45
46 /// <summary>Чистая геометрия: primary по центру ряда, P+M слева или справа от него.</summary>
47 internal static void ComputeForwardAndPmOrderedIndices(
48 int orderedScreenCount,
49 int primaryOrderedIndex,
50 bool pmGroupBeforeForwardInPresentation,
51 out int forwardOrderedIndex,
52 out int pmOrderedIndex)
53 {
54 forwardOrderedIndex = primaryOrderedIndex;
55 var pIdx = primaryOrderedIndex;
56
57 if (pmGroupBeforeForwardInPresentation)
58 {
59 // (P+M)(F): P+M слева от лобового (primary), если есть.
60 pmOrderedIndex = pIdx > 0
61 ? pIdx - 1
62 : (orderedScreenCount > pIdx + 1 ? pIdx + 1 : pIdx);
63 }
64 else
65 {
66 // (F)(P+M): P+M справа от primary, если есть.
67 pmOrderedIndex = pIdx < orderedScreenCount - 1
68 ? pIdx + 1
69 : (pIdx > 0 ? pIdx - 1 : pIdx);
70 }
71
72 if (pmOrderedIndex == forwardOrderedIndex && orderedScreenCount >= 2)
73 pmOrderedIndex = forwardOrderedIndex == 0 ? 1 : forwardOrderedIndex - 1;
74 }
75
76 private static int FindPrimaryOrderedIndex(IReadOnlyList<Screen> ordered, Screen? primary)
77 {
78 if (primary is null)
79 return 0;
80
81 for (var i = 0; i < ordered.Count; i++)
82 {
83 if (ReferenceEquals(ordered[i], primary))
84 return i;
85 }
86
87 for (var i = 0; i < ordered.Count; i++)
88 {
89 if (ordered[i].WorkingArea == primary.WorkingArea)
90 return i;
91 }
92
93 return 0;
94 }
95}
96
View only · write via MCP/CIDE