diff --git a/CommonWPF/CommonWPF.csproj b/CommonWPF/CommonWPF.csproj
new file mode 100644
index 0000000..a820073
--- /dev/null
+++ b/CommonWPF/CommonWPF.csproj
@@ -0,0 +1,76 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {1299AA2E-606D-4F3E-B3A9-3F9421E44667}
+ library
+ CommonWPF
+ CommonWPF
+ v4.6.2
+ 512
+ {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
+ 4
+ true
+
+
+ true
+ full
+ false
+ bin\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+
+
+ pdbonly
+ true
+ bin\Release\
+ TRACE
+ prompt
+ 4
+
+
+
+
+
+
+
+
+
+
+
+ 4.0
+
+
+
+
+
+
+
+
+
+ Code
+
+
+ True
+ True
+ Resources.resx
+
+
+ True
+ Settings.settings
+ True
+
+
+ ResXFileCodeGenerator
+ Resources.Designer.cs
+
+
+ SettingsSingleFileGenerator
+ Settings.Designer.cs
+
+
+
+
\ No newline at end of file
diff --git a/CommonWPF/InverseBooleanConverter.cs b/CommonWPF/InverseBooleanConverter.cs
new file mode 100644
index 0000000..89f32a6
--- /dev/null
+++ b/CommonWPF/InverseBooleanConverter.cs
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2019 faddenSoft
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using System;
+using System.Windows.Data;
+
+namespace CommonWPF {
+ ///
+ /// A value inverter for negating a boolean value (value --> !value).
+ ///
+ /// See https://stackoverflow.com/questions/1039636/how-to-bind-inverse-boolean-properties-in-wpf
+ ///
+ [ValueConversion(typeof(bool), typeof(bool))]
+ public class InverseBooleanConverter : IValueConverter {
+ public object Convert(object value, Type targetType, object parameter,
+ System.Globalization.CultureInfo culture) {
+ if (targetType != typeof(bool))
+ throw new InvalidOperationException("The target must be a boolean");
+
+ return !(bool)value;
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter,
+ System.Globalization.CultureInfo culture) {
+ throw new NotSupportedException();
+ }
+ }
+}
diff --git a/CommonWPF/MultiKeyInputGesture.cs b/CommonWPF/MultiKeyInputGesture.cs
new file mode 100644
index 0000000..8c2bed0
--- /dev/null
+++ b/CommonWPF/MultiKeyInputGesture.cs
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2018 faddenSoft
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows.Input;
+
+///
+/// Handle a multi-key input sequence for WPF windows.
+///
+///
+/// Also posted as https://stackoverflow.com/a/56452142/294248
+///
+/// Example:
+/// {RoutedUICommand}.InputGestures.Add(
+/// new MultiKeyInputGesture(new KeyGesture[] {
+/// new KeyGesture(Key.H, ModifierKeys.Control, "Ctrl+H"),
+/// new KeyGesture(Key.C, ModifierKeys.Control, "Ctrl+C")
+/// }) );
+///
+/// TODO: if you have more than one handler, the handler that completes a sequence will
+/// "eat" the final key, and the other handlers won't reset. Might need to define an event
+/// that all gesture objects subscribe to, so they all reset at once. In the mean time, the
+/// reset-after-time handler solves the problem if the user is moving slowly enough.
+///
+namespace CommonWPF {
+ public class MultiKeyInputGesture : InputGesture {
+ private const int MAX_PAUSE_MILLIS = 1500;
+
+ private InputGestureCollection mGestures = new InputGestureCollection();
+
+ private DateTime mLastWhen = DateTime.Now;
+ private int mCheckIdx;
+ private string mIdStr;
+
+
+ public MultiKeyInputGesture(KeyGesture[] keys) {
+ Debug.Assert(keys.Length > 0);
+
+ StringBuilder idSb = new StringBuilder();
+
+ // Grab a copy of the array contents.
+ foreach (KeyGesture kg in keys) {
+ mGestures.Add(kg);
+ idSb.Append(kg.DisplayString[kg.DisplayString.Length - 1]);
+ }
+ mIdStr = idSb.ToString();
+ }
+
+ public override bool Matches(object targetElement, InputEventArgs inputEventArgs) {
+ if (!(inputEventArgs is KeyEventArgs)) {
+ // does this actually happen?
+ return false;
+ }
+
+ DateTime now = DateTime.Now;
+ if ((now - mLastWhen).TotalMilliseconds > MAX_PAUSE_MILLIS) {
+ //Debug.WriteLine("MKIG " + mIdStr + ": too long since last key (" +
+ // (now - mLastWhen).TotalMilliseconds + " ms");
+ mCheckIdx = 0;
+ }
+ mLastWhen = now;
+
+ if (((KeyEventArgs)inputEventArgs).IsRepeat) {
+ // ignore key-repeat noise (especially from modifiers)
+ return false;
+ }
+
+ if (!mGestures[mCheckIdx].Matches(null, inputEventArgs)) {
+ if (mCheckIdx > 0) {
+ //Debug.WriteLine("MKIG " + mIdStr + ": no match, resetting");
+ mCheckIdx = 0;
+ }
+ return false;
+ }
+
+ //Debug.WriteLine("MKIG " + mIdStr + ": matched gesture #" + mCheckIdx);
+ mCheckIdx++;
+ if (mCheckIdx == mGestures.Count) {
+ //Debug.WriteLine("MKIG " + mIdStr + ": match");
+ mCheckIdx = 0;
+ inputEventArgs.Handled = true;
+ return true;
+ }
+
+ return false;
+ }
+ }
+}
diff --git a/CommonWPF/Properties/AssemblyInfo.cs b/CommonWPF/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..e089079
--- /dev/null
+++ b/CommonWPF/Properties/AssemblyInfo.cs
@@ -0,0 +1,55 @@
+using System.Reflection;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Windows;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("CommonWPF")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("CommonWPF")]
+[assembly: AssemblyCopyright("Copyright © 2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+//In order to begin building localizable applications, set
+//CultureYouAreCodingWith in your .csproj file
+//inside a . For example, if you are using US english
+//in your source files, set the to en-US. Then uncomment
+//the NeutralResourceLanguage attribute below. Update the "en-US" in
+//the line below to match the UICulture setting in the project file.
+
+//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
+
+
+[assembly:ThemeInfo(
+ ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
+ //(used if a resource is not found in the page,
+ // or application resource dictionaries)
+ ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
+ //(used if a resource is not found in the page,
+ // app, or any theme specific resource dictionaries)
+)]
+
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/CommonWPF/Properties/Resources.Designer.cs b/CommonWPF/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..4720be0
--- /dev/null
+++ b/CommonWPF/Properties/Resources.Designer.cs
@@ -0,0 +1,62 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace CommonWPF.Properties {
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if ((resourceMan == null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("CommonWPF.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/CommonWPF/Properties/Resources.resx b/CommonWPF/Properties/Resources.resx
new file mode 100644
index 0000000..af7dbeb
--- /dev/null
+++ b/CommonWPF/Properties/Resources.resx
@@ -0,0 +1,117 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/CommonWPF/Properties/Settings.Designer.cs b/CommonWPF/Properties/Settings.Designer.cs
new file mode 100644
index 0000000..926afbe
--- /dev/null
+++ b/CommonWPF/Properties/Settings.Designer.cs
@@ -0,0 +1,30 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace CommonWPF.Properties
+{
+
+
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")]
+ internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase
+ {
+
+ private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
+
+ public static Settings Default
+ {
+ get
+ {
+ return defaultInstance;
+ }
+ }
+ }
+}
diff --git a/CommonWPF/Properties/Settings.settings b/CommonWPF/Properties/Settings.settings
new file mode 100644
index 0000000..033d7a5
--- /dev/null
+++ b/CommonWPF/Properties/Settings.settings
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SourceGenWPF/MainController.cs b/SourceGenWPF/MainController.cs
index 5f12fec..7b714d0 100644
--- a/SourceGenWPF/MainController.cs
+++ b/SourceGenWPF/MainController.cs
@@ -54,10 +54,10 @@ namespace SourceGenWPF {
///
/// Current code list view selection. The length will match the DisplayList Count.
- ///
- /// A simple foreach through codeListView.SelectedIndices on a 500K-line data set
- /// takes about 2.5 seconds on a fast Win10 x64 machine. Fortunately the control
- /// notifies us of changes to the selection, so we can track it ourselves.
+ ///
+ /// WinForms was bad -- a simple foreach through SelectedIndices on a 500K-line data set
+ /// took about 2.5 seconds on a fast Win10 x64 machine. In WPF you get a list of
+ /// selected objects, which is fine unless what you really want is the line number.
///
private VirtualListViewSelection mCodeViewSelection = new VirtualListViewSelection();
#endif
diff --git a/SourceGenWPF/ProjWin/MainWindow.xaml b/SourceGenWPF/ProjWin/MainWindow.xaml
index 3bec1cf..fc7f655 100644
--- a/SourceGenWPF/ProjWin/MainWindow.xaml
+++ b/SourceGenWPF/ProjWin/MainWindow.xaml
@@ -45,6 +45,10 @@ limitations under the License.
Ctrl+Shift+A
+
+
+
+
@@ -56,6 +60,10 @@ limitations under the License.
+
+
+
+
@@ -106,10 +114,10 @@ limitations under the License.
-
-
-
-
+
+
+
+
diff --git a/SourceGenWPF/ProjWin/MainWindow.xaml.cs b/SourceGenWPF/ProjWin/MainWindow.xaml.cs
index 418fb42..bb90350 100644
--- a/SourceGenWPF/ProjWin/MainWindow.xaml.cs
+++ b/SourceGenWPF/ProjWin/MainWindow.xaml.cs
@@ -31,6 +31,8 @@ using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
+using CommonWPF;
+
namespace SourceGenWPF.ProjWin {
///
/// Interaction logic for MainWindow.xaml
@@ -61,10 +63,40 @@ namespace SourceGenWPF.ProjWin {
mMainCtrl = new MainController(this);
+ AddMultiKeyGestures();
+
//GridView gv = (GridView)codeListView.View;
//gv.Columns[0].Width = 50;
}
+ private void AddMultiKeyGestures() {
+ RoutedUICommand ruic;
+
+ ruic = (RoutedUICommand)FindResource("HintAsCodeEntryPoint");
+ ruic.InputGestures.Add(
+ new MultiKeyInputGesture(new KeyGesture[] {
+ new KeyGesture(Key.H, ModifierKeys.Control, "Ctrl+H"),
+ new KeyGesture(Key.C, ModifierKeys.Control, "Ctrl+C")
+ }));
+ ruic = (RoutedUICommand)FindResource("HintAsDataStart");
+ ruic.InputGestures.Add(
+ new MultiKeyInputGesture(new KeyGesture[] {
+ new KeyGesture(Key.H, ModifierKeys.Control, "Ctrl+H"),
+ new KeyGesture(Key.D, ModifierKeys.Control, "Ctrl+D")
+ }));
+ ruic = (RoutedUICommand)FindResource("HintAsInlineData");
+ ruic.InputGestures.Add(
+ new MultiKeyInputGesture(new KeyGesture[] {
+ new KeyGesture(Key.H, ModifierKeys.Control, "Ctrl+H"),
+ new KeyGesture(Key.I, ModifierKeys.Control, "Ctrl+I")
+ }));
+ ruic = (RoutedUICommand)FindResource("RemoveHints");
+ ruic.InputGestures.Add(
+ new MultiKeyInputGesture(new KeyGesture[] {
+ new KeyGesture(Key.H, ModifierKeys.Control, "Ctrl+H"),
+ new KeyGesture(Key.R, ModifierKeys.Control, "Ctrl+R")
+ }));
+ }
private void Window_Loaded(object sender, RoutedEventArgs e) {
mMainCtrl.WindowLoaded();
@@ -135,6 +167,22 @@ namespace SourceGenWPF.ProjWin {
Debug.WriteLine("assembling");
}
+ private void HintAsCodeEntryPoint_Executed(object sender, ExecutedRoutedEventArgs e) {
+ Debug.WriteLine("hint as code entry point");
+ }
+
+ private void HintAsDataStart_Executed(object sender, ExecutedRoutedEventArgs e) {
+ Debug.WriteLine("hint as data start");
+ }
+
+ private void HintAsInlineData_Executed(object sender, ExecutedRoutedEventArgs e) {
+ Debug.WriteLine("hint as inline data");
+ }
+
+ private void RemoveHints_Executed(object sender, ExecutedRoutedEventArgs e) {
+ Debug.WriteLine("remove hints");
+ }
+
private void SelectAllCmd_Executed(object sender, ExecutedRoutedEventArgs e) {
DateTime start = DateTime.Now;
diff --git a/SourceGenWPF/SourceGenWPF.csproj b/SourceGenWPF/SourceGenWPF.csproj
index 1bb2e95..d67e810 100644
--- a/SourceGenWPF/SourceGenWPF.csproj
+++ b/SourceGenWPF/SourceGenWPF.csproj
@@ -183,6 +183,10 @@
{a2993eac-35d8-4768-8c54-152b4e14d69c}
CommonUtil
+
+ {1299aa2e-606d-4f3e-b3a9-3f9421e44667}
+ CommonWPF
+
{70f04543-9e46-4ad3-875a-160fd198c0ff}
PluginCommon
diff --git a/WorkBench.sln b/WorkBench.sln
index 4c632ec..f6b05fa 100644
--- a/WorkBench.sln
+++ b/WorkBench.sln
@@ -26,6 +26,11 @@ EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommonWinForms", "CommonWinForms\CommonWinForms.csproj", "{08EC328D-078E-4236-B574-BE6B3FD85915}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SourceGenWPF", "SourceGenWPF\SourceGenWPF.csproj", "{30C35BBC-B9ED-4723-8F9D-597D51CCB13A}"
+ ProjectSection(ProjectDependencies) = postProject
+ {1299AA2E-606D-4F3E-B3A9-3F9421E44667} = {1299AA2E-606D-4F3E-B3A9-3F9421E44667}
+ EndProjectSection
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CommonWPF", "CommonWPF\CommonWPF.csproj", "{1299AA2E-606D-4F3E-B3A9-3F9421E44667}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -69,6 +74,10 @@ Global
{30C35BBC-B9ED-4723-8F9D-597D51CCB13A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{30C35BBC-B9ED-4723-8F9D-597D51CCB13A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{30C35BBC-B9ED-4723-8F9D-597D51CCB13A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1299AA2E-606D-4F3E-B3A9-3F9421E44667}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1299AA2E-606D-4F3E-B3A9-3F9421E44667}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1299AA2E-606D-4F3E-B3A9-3F9421E44667}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1299AA2E-606D-4F3E-B3A9-3F9421E44667}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE