diff --git a/Plant3D2026/P_Rec_Annot/bundle/P_Rec_Annot.bundle/PackageContents.xml b/Plant3D2026/P_Rec_Annot/bundle/P_Rec_Annot.bundle/PackageContents.xml index 202ac89..9c5badc 100644 --- a/Plant3D2026/P_Rec_Annot/bundle/P_Rec_Annot.bundle/PackageContents.xml +++ b/Plant3D2026/P_Rec_Annot/bundle/P_Rec_Annot.bundle/PackageContents.xml @@ -1,5 +1,5 @@ - + diff --git a/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Core/ManualDatumResolver.cs b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Core/ManualDatumResolver.cs new file mode 100644 index 0000000..683b5ea --- /dev/null +++ b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Core/ManualDatumResolver.cs @@ -0,0 +1,9 @@ +namespace PRecAnnot.Core; + +public enum ManualDatumMode { Absolute, Relative } + +public static class ManualDatumResolver +{ + public static double Resolve(double sourceElevation, ManualDatumMode mode, double offset) => + mode == ManualDatumMode.Absolute ? sourceElevation : sourceElevation + offset; +} diff --git a/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/EntryPoint.cs b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/EntryPoint.cs index 2a819ed..406e2da 100644 --- a/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/EntryPoint.cs +++ b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/EntryPoint.cs @@ -370,12 +370,27 @@ internal static class RibbonIntegration if (tab is null) { tab = new RibbonTab { Id = TabId, Title = "Промхимпроект" }; ribbon.Tabs.Add(tab); } var panel = tab.Panels.FirstOrDefault(x => string.Equals(x.Source?.Id, PanelId, StringComparison.OrdinalIgnoreCase)); if (panel is not null) { RuntimeDiagnostics.Write("RibbonAlreadyExists", resultStatus: "AlreadyExists"); RuntimeDiagnostics.Write("RibbonInitializationCompleted", resultStatus: "AlreadyExists"); return; } + // Keep the existing legacy-compatible PHP_REC_ANNOT action and expose the + // production command surface from the same composite panel. var source = new RibbonPanelSource { Id = PanelId, Title = "Аннотации" }; source.Items.Add(new RibbonButton { Id = ButtonId, Text = "Аннотировать", ShowText = true, CommandParameter = "PHP_REC_ANNOT " }); + AddButton(source, "LineNumber", "Line number", "PXP-LN"); + AddButton(source, "LineConnections", "Line connections", "PXP-ALC"); + AddButton(source, "AutoElevation", "Auto elevation", "PXP-AE"); + AddButton(source, "InsertElevation", "Insert elevation", "PXP-IE"); + AddButton(source, "OrthoAnnotate", "Ortho annotate", "PXP-OA"); + AddButton(source, "AnnotateView", "Annotate view", "PXP-AAV"); + AddButton(source, "ManualPalette", "Manual annotations", "mto-ma"); tab.Panels.Add(new RibbonPanel { Source = source }); RuntimeDiagnostics.Write("RibbonInitializationCompleted", resultStatus: "Created"); } + private static void AddButton(RibbonPanelSource? source, string suffix, string text, string command) + { + if (source is null) return; + source.Items.Add(new RibbonButton { Id = $"{PanelId}.{suffix}", Text = text, ShowText = true, CommandParameter = command + " " }); + } + public static void Terminate() { if (!deferred) return; diff --git a/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/ManualAnnotationPalette.cs b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/ManualAnnotationPalette.cs index d596ca8..ae7909a 100644 --- a/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/ManualAnnotationPalette.cs +++ b/Plant3D2026/P_Rec_Annot/src/PRecAnnot.Plant3D2026/ManualAnnotationPalette.cs @@ -47,6 +47,9 @@ internal sealed class ManualAnnotationControl : WinForms.UserControl private readonly WinForms.Button place = new() { Text = "Place", AutoSize = true }; private readonly WinForms.Button reconnect = new() { Text = "Reconnect / refresh", AutoSize = true }; private readonly WinForms.Button help = new() { Text = "Help", AutoSize = true }; + private readonly WinForms.RadioButton absoluteDatum = new() { Text = "Absolute datum", AutoSize = true, Checked = true }; + private readonly WinForms.RadioButton relativeDatum = new() { Text = "Relative datum", AutoSize = true }; + private readonly WinForms.NumericUpDown datumOffset = new() { DecimalPlaces = 3, Minimum = -100000, Maximum = 100000, Increment = 0.001M, Enabled = false }; private readonly Dictionary kinds = new(); public ManualAnnotationControl() { @@ -55,8 +58,11 @@ internal sealed class ManualAnnotationControl : WinForms.UserControl Add("Instrument position", ManualAnnotationKind.InstrumentPosition); Add("Section elevation", ManualAnnotationKind.SectionElevation); Add("Instrument connection point", ManualAnnotationKind.InstrumentConnection); Add("AutoCAD block", ManualAnnotationKind.AutoCadBlock); Add("Platform elevation", ManualAnnotationKind.PlatformElevation); Add("Other elevation", ManualAnnotationKind.OtherElevation); place.Click += (_, _) => Place(); reconnect.Click += (_, _) => Reconnect(); help.Click += (_, _) => OpenHelp(); + var datum = new WinForms.FlowLayoutPanel { Dock = WinForms.DockStyle.Top, AutoSize = true }; datum.Controls.Add(absoluteDatum); datum.Controls.Add(relativeDatum); datum.Controls.Add(datumOffset); + absoluteDatum.CheckedChanged += (_, _) => datumOffset.Enabled = relativeDatum.Checked; + relativeDatum.CheckedChanged += (_, _) => datumOffset.Enabled = relativeDatum.Checked; var actions = new WinForms.FlowLayoutPanel { Dock = WinForms.DockStyle.Top, AutoSize = true }; actions.Controls.Add(place); actions.Controls.Add(reconnect); actions.Controls.Add(help); - Controls.Add(actions); Controls.Add(choices); RefreshTheme(); + Controls.Add(datum); Controls.Add(actions); Controls.Add(choices); RefreshTheme(); } private void Add(string text, ManualAnnotationKind kind, bool selected = false) { var button = new WinForms.RadioButton { Text = text, AutoSize = true, Checked = selected }; kinds.Add(button, kind); choices.Controls.Add(button); } public void RefreshAvailability() { var available = AcadApplication.DocumentManager.MdiActiveDocument is not null && PlantApplication.CurrentProject is not null; place.Enabled = available; reconnect.Enabled = available; RefreshTheme(); } diff --git a/Plant3D2026/P_Rec_Annot/tests/PRecAnnot.Core.Tests/ManualDatumResolverTests.cs b/Plant3D2026/P_Rec_Annot/tests/PRecAnnot.Core.Tests/ManualDatumResolverTests.cs new file mode 100644 index 0000000..fcb3928 --- /dev/null +++ b/Plant3D2026/P_Rec_Annot/tests/PRecAnnot.Core.Tests/ManualDatumResolverTests.cs @@ -0,0 +1,17 @@ +using PRecAnnot.Core; + +namespace PRecAnnot.Core.Tests; + +public sealed class ManualDatumResolverTests +{ + [Theory] + [InlineData(12.5, ManualDatumMode.Absolute, 99, 12.5)] + [InlineData(12.5, ManualDatumMode.Relative, 3.5, 16)] + [InlineData(12.5, ManualDatumMode.Relative, -3.5, 9)] + [InlineData(0, ManualDatumMode.Relative, 0, 0)] + [InlineData(-8, ManualDatumMode.Relative, 2, -6)] + public void Resolve_preserves_legacy_absolute_and_relative_datum(double source, ManualDatumMode mode, double offset, double expected) + { + Assert.Equal(expected, ManualDatumResolver.Resolve(source, mode, offset), 8); + } +} diff --git a/Plant3D2026/P_Rec_Annot/tools/Build-Bundle.ps1 b/Plant3D2026/P_Rec_Annot/tools/Build-Bundle.ps1 index 5f428c4..35e0ab8 100644 --- a/Plant3D2026/P_Rec_Annot/tools/Build-Bundle.ps1 +++ b/Plant3D2026/P_Rec_Annot/tools/Build-Bundle.ps1 @@ -10,6 +10,6 @@ Get-ChildItem $output -File -Filter '*.dll' | Copy-Item -Destination $contents - Copy-Item (Join-Path $PSScriptRoot '..\bundle\P_Rec_Annot.bundle\PackageContents.xml') $bundleRoot -Force $modules=@('PHP_REC_ANNOT','AnnotateLineNumbers','AutoLinenumberConnections','AutoElevation','InsertElevation','ExtentsIntersect','DataLinksRead') $assemblies=Get-ChildItem $contents -File -Filter '*.dll' | Sort-Object Name | ForEach-Object { [ordered]@{ name=$_.Name; sha256=(Get-FileHash $_.FullName -Algorithm SHA256).Hash.ToLowerInvariant(); required=$true } } -$manifest=[ordered]@{ schemaVersion=1; package='P_Rec_Annot'; version='0.2.1'; modules=$modules; assemblies=$assemblies } +$manifest=[ordered]@{ schemaVersion=1; package='P_Rec_Annot'; version='0.2.2'; modules=$modules; assemblies=$assemblies } $manifest | ConvertTo-Json -Depth 5 | Set-Content (Join-Path $bundleRoot 'Contents\module-manifest.json') -Encoding utf8 Write-Host 'Bundle assembly build completed; deployment is intentionally not performed.'