| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent bc13030 commit f938cfa
46 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,113 @@ | |||
| 1 | + using MW5.Plugins.AdvancedSnapping.Services; | ||
| 2 | + using MW5.Plugins.AdvancedSnapping.Context; | ||
| 3 | + using MW5.Plugins.AdvancedSnapping.Listeners; | ||
| 4 | + using MW5.Plugins.AdvancedSnapping.Views; | ||
| 5 | + using MW5.Plugins.Concrete; | ||
| 6 | + using MW5.Plugins.Interfaces; | ||
| 7 | + using MW5.Plugins.Mef; | ||
| 8 | + using MW5.Plugins.Mvp; | ||
| 9 | + using MW5.Plugins.ShapeEditor.Context; | ||
| 10 | + using System.Collections.Generic; | ||
| 11 | + using System.Windows; | ||
| 12 | + | ||
| 13 | + namespace MW5.Plugins.AdvancedSnapping | ||
| 14 | + { | ||
| 15 | + [MapWindowPlugin(loadOnStartUp: true, After = new[] { "Shape Editor" })] | ||
| 16 | + public class AdvancedSnappingPlugin : BasePlugin | ||
| 17 | + { | ||
| 18 | + #region private variables | ||
| 19 | + private IAppContext _context; | ||
| 20 | + private IAnchorService _anchorService; | ||
| 21 | + private ISnapRestrictionService _snapRestrictionService; | ||
| 22 | + #endregion | ||
| 23 | + | ||
| 24 | + #region Properties: | ||
| 25 | + public bool CanSnapPerpendicular | ||
| 26 | + { | ||
| 27 | + get => _anchorService.ReferenceSegment != null; | ||
| 28 | + } | ||
| 29 | + | ||
| 30 | + public bool CanSnapParallel | ||
| 31 | + { | ||
| 32 | + get => _anchorService.ReferenceSegment != null; | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + public bool CanSnapBearing | ||
| 36 | + { | ||
| 37 | + get => true; | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + public bool CanSnapDistance | ||
| 41 | + { | ||
| 42 | + get => true; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + public bool HasActiveSnapLines | ||
| 46 | + { | ||
| 47 | + get => _snapRestrictionService.HasActiveRestrictions; | ||
| 48 | + } | ||
| 49 | + | ||
| 50 | + public bool AutoClearSnapLines | ||
| 51 | + { | ||
| 52 | + get => _snapRestrictionService.AutoClear; | ||
| 53 | + } | ||
| 54 | + | ||
| 55 | + #endregion | ||
| 56 | + | ||
| 57 | + #region Initialization | ||
| 58 | + | ||
| 59 | + public override void Initialize(IAppContext context) | ||
| 60 | + { | ||
| 61 | + _context = context; | ||
| 62 | + | ||
| 63 | + WPFWorkArounds(); | ||
| 64 | + | ||
| 65 | + IApplicationContainer container = context.Container; | ||
| 66 | + container.GetInstance<ContextMenuExtender>(); | ||
| 67 | + container.GetInstance<ContextMenuView>(); | ||
| 68 | + container.GetInstance<MapListener>(); | ||
| 69 | + _anchorService = container.GetSingleton<IAnchorService>(); | ||
| 70 | + _snapRestrictionService = container.GetSingleton<ISnapRestrictionService>(); | ||
| 71 | + } | ||
| 72 | + | ||
| 73 | + protected override void RegisterServices(IApplicationContainer container) | ||
| 74 | + { | ||
| 75 | + CompositionRoot.Compose(container); | ||
| 76 | + } | ||
| 77 | + | ||
| 78 | + internal void WPFWorkArounds() | ||
| 79 | + { | ||
| 80 | + // Makes sure we have a WPF application, windows forms app does not initialize this for us: | ||
| 81 | + WindowExtensions.MainWindowHandle = _context.View.MainForm.Handle; | ||
| 82 | + | ||
| 83 | + WindowExtensions.EnsureApplicationResources(); | ||
| 84 | + | ||
| 85 | + if (null == Application.Current) | ||
| 86 | + { | ||
| 87 | + var app = new Application(); | ||
| 88 | + System.Windows.Forms.Application.EnableVisualStyles(); | ||
| 89 | + } | ||
| 90 | + } | ||
| 91 | + | ||
| 92 | + #endregion | ||
| 93 | + | ||
| 94 | + #region Plugin settings | ||
| 95 | + | ||
| 96 | + public override void SetSettings(IDictionary<string, string> settings) | ||
| 97 | + { | ||
| 98 | + base.SetSettings(settings); | ||
| 99 | + if (settings.TryGetValue("AutoClearSnapLines", out string autoClearSnapLines)) | ||
| 100 | + _snapRestrictionService.AutoClear = bool.Parse(autoClearSnapLines); | ||
| 101 | + } | ||
| 102 | + | ||
| 103 | + public override IDictionary<string, string> GetSettings() | ||
| 104 | + { | ||
| 105 | + var settings = base.GetSettings(); | ||
| 106 | + settings["AutoClearSnapLines"] = AutoClearSnapLines.ToString(); | ||
| 107 | + return settings; | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + #endregion | ||
| 111 | + | ||
| 112 | + } | ||
| 113 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,21 @@ | |||
| 1 | + using MW5.Plugins.AdvancedSnapping.Context; | ||
| 2 | + using MW5.Plugins.AdvancedSnapping.Listeners; | ||
| 3 | + using MW5.Plugins.AdvancedSnapping.Services; | ||
| 4 | + using MW5.Plugins.Mvp; | ||
| 5 | + | ||
| 6 | + namespace MW5.Plugins.AdvancedSnapping | ||
| 7 | + { | ||
| 8 | + internal static class CompositionRoot | ||
| 9 | + { | ||
| 10 | + public static void Compose(IApplicationContainer container) | ||
| 11 | + { | ||
| 12 | + container | ||
| 13 | + .RegisterSingleton<ISnapRestrictionService, SnapRestrictionService>() | ||
| 14 | + .RegisterSingleton<IAnchorService, AnchorService>() | ||
| 15 | + .RegisterSingleton<IDrawingService, DrawingService>() | ||
| 16 | + .RegisterSingleton<ContextMenuExtender>() | ||
| 17 | + .RegisterSingleton<MapListener>(); | ||
| 18 | + | ||
| 19 | + } | ||
| 20 | + } | ||
| 21 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,15 @@ | |||
| 1 | + namespace MW5.Plugins.AdvancedSnapping.Context | ||
| 2 | + { | ||
| 3 | + public enum AdvancedSnappingCommand | ||
| 4 | + { | ||
| 5 | + None = 0, | ||
| 6 | + SnapParallel = 1, | ||
| 7 | + SnapPerpendicular = 2, | ||
| 8 | + SnapBearing = 3, | ||
| 9 | + | ||
| 10 | + SnapDistance = 10, | ||
| 11 | + | ||
| 12 | + ClearSnapLines = 20, | ||
| 13 | + AutoClearSnapLines = 21 | ||
| 14 | + } | ||
| 15 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,184 @@ | |||
| 1 | + using System; | ||
| 2 | + using System.Collections.Generic; | ||
| 3 | + using System.Drawing; | ||
| 4 | + using System.Linq; | ||
| 5 | + using System.Windows.Forms; | ||
| 6 | + using MW5.Api.Enums; | ||
| 7 | + using MW5.Plugins.Interfaces; | ||
| 8 | + using MW5.Plugins.Mvp; | ||
| 9 | + using MW5.Plugins.AdvancedSnapping.Services; | ||
| 10 | + using MW5.Api.Interfaces; | ||
| 11 | + | ||
| 12 | + namespace MW5.Plugins.AdvancedSnapping.Context | ||
| 13 | + { | ||
| 14 | + public class ContextMenuExtender : CommandDispatcher<ShapeEditor.Context.ContextMenuView, AdvancedSnappingCommand> | ||
| 15 | + { | ||
| 16 | + private readonly IAppContext _context; | ||
| 17 | + private readonly AdvancedSnappingPlugin _plugin; | ||
| 18 | + private readonly ShapeEditor.Context.ContextMenuPresenter _shapeEditorContextMenuPresenter; | ||
| 19 | + private readonly ISnapRestrictionService _snapRestrictionService; | ||
| 20 | + private readonly IAnchorService _anchorService; | ||
| 21 | + | ||
| 22 | + public bool IsOpen | ||
| 23 | + { | ||
| 24 | + get => _shapeEditorContextMenuPresenter.VertexMenu.Visible; | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + public ContextMenuExtender(IAppContext context, | ||
| 28 | + AdvancedSnappingPlugin plugin, | ||
| 29 | + ShapeEditor.Context.ContextMenuView view, | ||
| 30 | + ISnapRestrictionService snapRestrictionService, | ||
| 31 | + IAnchorService anchorService, | ||
| 32 | + ShapeEditor.Context.ContextMenuPresenter shapeEditorContextMenuPresenter) : base(view) | ||
| 33 | + { | ||
| 34 | + _context = context ?? throw new ArgumentNullException("context"); | ||
| 35 | + _plugin = plugin ?? throw new ArgumentNullException("plugin"); | ||
| 36 | + _shapeEditorContextMenuPresenter = shapeEditorContextMenuPresenter ?? throw new ArgumentNullException("shapeEditorContextMenuPresenter"); | ||
| 37 | + _snapRestrictionService = snapRestrictionService ?? throw new ArgumentNullException("snapRestrictionService"); | ||
| 38 | + _anchorService = anchorService ?? throw new ArgumentNullException("anchorService"); | ||
| 39 | + | ||
| 40 | + AddItems(); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + public void UpdateStates() | ||
| 44 | + { | ||
| 45 | + foreach (var item in items) | ||
| 46 | + item.Visible = false; | ||
| 47 | + | ||
| 48 | + var layer = _context.Map.Layers.Current; | ||
| 49 | + if (!layer?.FeatureSet?.InteractiveEditing ?? true) | ||
| 50 | + return; | ||
| 51 | + | ||
| 52 | + foreach (var item in items) | ||
| 53 | + { | ||
| 54 | + item.Enabled = false; | ||
| 55 | + switch (item.Name) | ||
| 56 | + { | ||
| 57 | + case "ctxSnapBearing": | ||
| 58 | + item.Enabled = _plugin.CanSnapBearing; | ||
| 59 | + item.Visible = item.Enabled; | ||
| 60 | + break; | ||
| 61 | + case "ctxSnapDistance": | ||
| 62 | + item.Enabled = _plugin.CanSnapDistance; | ||
| 63 | + item.Visible = item.Enabled; | ||
| 64 | + break; | ||
| 65 | + case "ctxSnapParallel": | ||
| 66 | + item.Enabled = _plugin.CanSnapParallel; | ||
| 67 | + item.Visible = item.Enabled; | ||
| 68 | + break; | ||
| 69 | + case "ctxSnapPerpendicular": | ||
| 70 | + item.Enabled = _plugin.CanSnapPerpendicular; | ||
| 71 | + item.Visible = item.Enabled; | ||
| 72 | + break; | ||
| 73 | + case "ctxClearSnapLines": | ||
| 74 | + item.Enabled = _plugin.HasActiveSnapLines; | ||
| 75 | + item.Visible = item.Enabled; | ||
| 76 | + break; | ||
| 77 | + case "ctxAutoClearSnapLines": | ||
| 78 | + item.Checked = _plugin.AutoClearSnapLines; | ||
| 79 | + item.Enabled = item.Visible = true; | ||
| 80 | + break; | ||
| 81 | + } | ||
| 82 | + } | ||
| 83 | + } | ||
| 84 | + | ||
| 85 | + /// <summary> | ||
| 86 | + /// Adds context menu items to the shape editor | ||
| 87 | + /// </summary> | ||
| 88 | + private void AddItems() | ||
| 89 | + { | ||
| 90 | + // Keep track of items | ||
| 91 | + items = new List<ToolStripMenuItem>(); | ||
| 92 | + | ||
| 93 | + // Add them to the existing context menu | ||
| 94 | + var index = _shapeEditorContextMenuPresenter.VertexMenu.Items.IndexOfKey("ctxSnapping"); | ||
| 95 | + index = AddItem(index, "ctxSnapParallel", "Parallel to this", "S", MW5.Plugins.AdvancedSnapping.Properties.Resources.parallel); | ||
| 96 | + index = AddItem(index, "ctxSnapPerpendicular", "Perpendicular to this", "F", MW5.Plugins.AdvancedSnapping.Properties.Resources.perpendicular); | ||
| 97 | + index = AddItem(index, "ctxSnapDistance", "Distance from this", "D", MW5.Plugins.AdvancedSnapping.Properties.Resources.distance); | ||
| 98 | + index = AddItem(index, "ctxSnapBearing", "Bearing from this", "G", MW5.Plugins.AdvancedSnapping.Properties.Resources.bearing); | ||
| 99 | + | ||
| 100 | + // Put this one at the bottom | ||
| 101 | + index = _shapeEditorContextMenuPresenter.VertexMenu.Items.IndexOfKey("ctxClearEditor"); | ||
| 102 | + index = AddItem(index, "ctxClearSnapLines", "Clear snap lines", "", null); | ||
| 103 | + | ||
| 104 | + var options = _shapeEditorContextMenuPresenter.VertexMenu.Items["ctxSnapping"] as ToolStripMenuItem; | ||
| 105 | + var ctxAutoClearSnapLines = new ToolStripMenuItem { | ||
| 106 | + Name = "ctxAutoClearSnapLines", | ||
| 107 | + Text = "Auto-clear snap lines" | ||
| 108 | + }; | ||
| 109 | + options.DropDownItems.Add(ctxAutoClearSnapLines); | ||
| 110 | + items.Add(ctxAutoClearSnapLines); | ||
| 111 | + | ||
| 112 | + // Call this to hook up event handlers: | ||
| 113 | + InitMenu(new ToolStripItemCollection(_shapeEditorContextMenuPresenter.VertexMenu, items.ToArray())); | ||
| 114 | + } | ||
| 115 | + | ||
| 116 | + private IList<ToolStripMenuItem> items; | ||
| 117 | + | ||
| 118 | + private int AddItem(int index, string name, string text, string shortCutKey, Bitmap image) | ||
| 119 | + { | ||
| 120 | + var item = new ToolStripMenuItem(); | ||
| 121 | + item.Name = name; | ||
| 122 | + item.Text = text; | ||
| 123 | + item.ShortcutKeyDisplayString = shortCutKey; | ||
| 124 | + if (image != null) item.Image = image; | ||
| 125 | + _shapeEditorContextMenuPresenter.VertexMenu.Items.Insert(index++, item); | ||
| 126 | + items.Add(item); | ||
| 127 | + return index; | ||
| 128 | + } | ||
| 129 | + | ||
| 130 | + public override void RunCommand(AdvancedSnappingCommand command) | ||
| 131 | + { | ||
| 132 | + | ||
| 133 | + var anchor = _anchorService.PrimaryAnchor; | ||
| 134 | + var userAnchorLocation = _anchorService.UserAnchorLocation; | ||
| 135 | + var segment = _anchorService.ReferenceSegment; | ||
| 136 | + | ||
| 137 | + var map = _context.Map; | ||
| 138 | + switch (command) | ||
| 139 | + { | ||
| 140 | + case AdvancedSnappingCommand.ClearSnapLines: | ||
| 141 | + _snapRestrictionService.Clear(); | ||
| 142 | + break; | ||
| 143 | + case AdvancedSnappingCommand.SnapDistance: | ||
| 144 | + _snapRestrictionService.SnapDistance(anchor, handle: map.GeometryEditor.NumPoints); | ||
| 145 | + break; | ||
| 146 | + case AdvancedSnappingCommand.SnapBearing: | ||
| 147 | + _snapRestrictionService.SnapBearing(anchor, handle: map.GeometryEditor.NumPoints); | ||
| 148 | + break; | ||
| 149 | + case AdvancedSnappingCommand.SnapParallel: | ||
| 150 | + if (segment != null) | ||
| 151 | + { | ||
| 152 | + // If we're snapping parallel, ask user how far if he's not yet digitizing | ||
| 153 | + //bool needsUserInput = (anchor == _anchorFeatureService.LastUserLocation); | ||
| 154 | + _snapRestrictionService.SnapParallel( | ||
| 155 | + _context.Map.GeometryEditor.NumPoints > 0 ? anchor : segment.Item1, | ||
| 156 | + segment.Item1, segment.Item2, | ||
| 157 | + offsetAnchor: _context.Map.GeometryEditor.NumPoints > 0 ? segment.Item1 : null, | ||
| 158 | + handle: map.GeometryEditor.NumPoints | ||
| 159 | + ); | ||
| 160 | + } | ||
| 161 | + break; | ||
| 162 | + case AdvancedSnappingCommand.SnapPerpendicular: | ||
| 163 | + if (segment != null) | ||
| 164 | + { | ||
| 165 | + // If we're snapping parallel, ask user how far if he's not yet digitizing | ||
| 166 | + //bool needsUserInput = (anchor == _anchorService.LastUserLocation); | ||
| 167 | + _snapRestrictionService.SnapPerpendicular( | ||
| 168 | + anchor, | ||
| 169 | + segment.Item1, segment.Item2, | ||
| 170 | + handle: map.GeometryEditor.NumPoints | ||
| 171 | + ); | ||
| 172 | + } | ||
| 173 | + break; | ||
| 174 | + case AdvancedSnappingCommand.AutoClearSnapLines: | ||
| 175 | + _snapRestrictionService.AutoClear = !_snapRestrictionService.AutoClear; | ||
| 176 | + UpdateStates(); | ||
| 177 | + break; | ||
| 178 | + } | ||
| 179 | + | ||
| 180 | + _context.View.Update(); | ||
| 181 | + _context.Map.Redraw(RedrawType.SkipDataLayers); | ||
| 182 | + } | ||
| 183 | + } | ||
| 184 | + } | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments