├── .gitattributes
├── .gitignore
├── CONTRIBUTING.md
├── Demo
├── App.xaml
├── App.xaml.cs
├── Assets
│ ├── LockScreenLogo.scale-200.png
│ ├── SplashScreen.scale-200.png
│ ├── Square150x150Logo.scale-200.png
│ ├── Square44x44Logo.scale-200.png
│ ├── Square44x44Logo.targetsize-24_altform-unplated.png
│ ├── StoreLogo.png
│ └── Wide310x150Logo.scale-200.png
├── MainPage.xaml
├── MainPage.xaml.cs
├── MyCertificate.cs
├── MyScript.InteractiveInk.Demo.Uwp.csproj
├── MyScript.InteractiveInk.Demo.Uwp_TemporaryKey.pfx
├── Package.appxmanifest
└── Properties
│ ├── AssemblyInfo.cs
│ └── Default.rd.xml
├── GetStarted
├── App.xaml
├── App.xaml.cs
├── Assets
│ ├── LockScreenLogo.scale-200.png
│ ├── SplashScreen.scale-200.png
│ ├── Square150x150Logo.scale-200.png
│ ├── Square44x44Logo.scale-200.png
│ ├── Square44x44Logo.targetsize-24_altform-unplated.png
│ ├── StoreLogo.png
│ └── Wide310x150Logo.scale-200.png
├── MainPage.xaml
├── MainPage.xaml.cs
├── MyCertificate.cs
├── MyScript.InteractiveInk.GetStarted.Uwp.csproj
├── MyScript.InteractiveInk.GetStarted.Uwp_TemporaryKey.pfx
├── Package.appxmanifest
└── Properties
│ ├── AssemblyInfo.cs
│ └── Default.rd.xml
├── LICENSES
├── inter.txt
└── stix.pdf
├── MyScript.InteractiveInk.Examples.Uwp.sln
├── README.md
├── UIReferenceImplementation
├── Canvas.cs
├── Constants
│ └── StyleKeys.cs
├── Converters
│ └── BoolNegationConverter.cs
├── EditorListener.cs
├── Extensions
│ ├── Primitives.cs
│ └── SDK.cs
├── FontMetricsProvider.cs
├── ImageLoader.cs
├── ImagePainter.cs
├── Layer.cs
├── MyScript.InteractiveInk.UIReferenceImplementation.Uwp.csproj
├── Path.cs
├── Properties
│ ├── AssemblyInfo.cs
│ ├── MyScript.InteractiveInk.UIReferenceImplementation.rd.xml
│ └── iink_sdk_examples_uwp.UIRefImpl.rd.xml
├── RendererListener.cs
└── UserControls
│ ├── EditorUserControl.xaml
│ ├── EditorUserControl.xaml.cs
│ ├── InkToolbar.xaml
│ ├── InkToolbar.xaml.cs
│ ├── SmartGuideUserControl.xaml
│ └── SmartGuideUserControl.xaml.cs
├── configurations
├── Raw Content
│ ├── drawing.json
│ └── text_math_shape.json
└── interactivity.json
├── fonts
├── MyScriptInter-Bold.otf
├── MyScriptInter-Regular.otf
├── STIXTwoMath-Regular.otf
└── STIXTwoText-Italic.otf
└── getRecognitionAssets.ps1
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
3 | # git
4 | .gitignore text
5 |
6 | # source & misc files
7 | *.c text diff=cpp whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent,no-newline-at-eof
8 | *.cpp text diff=cpp whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent,no-newline-at-eof
9 | *.cs text diff=csharp whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent
10 | *.h text diff=cpp whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent,no-newline-at-eof
11 | *.hpp text diff=cpp whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent,no-newline-at-eof
12 | *.html text diff=html whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent
13 | *.java text diff=java whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent
14 | *.js text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent
15 | *.l text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent
16 | *.m text diff=objc whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent,no-newline-at-eof
17 | *.mm text diff=objc whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent,no-newline-at-eof
18 | *.pl text diff=perl whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent
19 | *.py text diff=python whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent
20 | *.rb text diff=ruby whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent
21 | *.tex text diff=text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent
22 | *.txt text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent
23 | *.xml text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent
24 | *.y text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent
25 | *.tsv text whitespace=-blank-at-eol,blank-at-eof,-space-before-tab,-tab-in-indent
26 | *.groovy text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent
27 |
28 | # Shell scripts
29 | *.sh diff=bash text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent eol=lf executable=maybe
30 | _sh/* text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent eol=lf executable=maybe
31 | *.bat text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent eol=crlf executable=maybe
32 | *.ps1 text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent eol=crlf executable=maybe
33 |
34 | # Python scripts
35 | *.py text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent eol=lf executable=maybe
36 |
37 | # Awk scripts
38 | *.awk text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent eol=lf
39 |
40 | # GNU Makefile
41 | Makefile text whitespace=blank-at-eol,blank-at-eof,space-before-tab eol=lf
42 |
43 | # CMake files
44 | CMakeLists.txt text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent eol=lf
45 | *.cmake text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent eol=lf
46 |
47 | # Autotools
48 | *.am text whitespace=blank-at-eol,blank-at-eof,space-before-tab eol=lf
49 |
50 | # Android
51 | *.mk text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent eol=lf
52 | *.gradle text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent
53 | gradlew text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent eol=lf executable
54 | gradlew.bat text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent eol=crlf executable=maybe
55 |
56 | # Xcode files
57 | *.pbxproj text whitespace=blank-at-eol,blank-at-eof,space-before-tab eol=lf
58 |
59 | # Visual Studio files
60 | *.sln text whitespace=blank-at-eol,blank-at-eof,space-before-tab eol=crlf bomb
61 | *.vcxproj text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent eol=crlf bomb
62 | *.vcxproj.filters text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent eol=crlf bomb
63 | *.csproj text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent eol=crlf bomb
64 | *.targets text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent eol=crlf bomb
65 | *.targets.template text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent eol=crlf bomb
66 | *.vsprops text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent eol=crlf bomb
67 | *.props text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent eol=crlf bomb
68 | *.xaml text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent eol=crlf bomb
69 | *.config text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent bomb=maybe
70 | *.resx text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent eol=crlf bomb
71 | *.settings text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent bomb=maybe
72 | *.appxmanifest text whitespace=blank-at-eol,blank-at-eof,space-before-tab,tab-in-indent eol=crlf bomb=maybe
73 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | bld/
21 | [Bb]in/
22 | [Oo]bj/
23 | [Ll]og/
24 |
25 | # Visual Studio 2015 cache/options directory
26 | .vs/
27 | # Uncomment if you have tasks that create the project's static files in wwwroot
28 | #wwwroot/
29 |
30 | # MSTest test Results
31 | [Tt]est[Rr]esult*/
32 | [Bb]uild[Ll]og.*
33 |
34 | # NUNIT
35 | *.VisualState.xml
36 | TestResult.xml
37 |
38 | # Build Results of an ATL Project
39 | [Dd]ebugPS/
40 | [Rr]eleasePS/
41 | dlldata.c
42 |
43 | # DNX
44 | project.lock.json
45 | project.fragment.lock.json
46 | artifacts/
47 |
48 | *_i.c
49 | *_p.c
50 | *_i.h
51 | *.ilk
52 | *.meta
53 | *.obj
54 | *.pch
55 | *.pdb
56 | *.pgc
57 | *.pgd
58 | *.rsp
59 | *.sbr
60 | *.tlb
61 | *.tli
62 | *.tlh
63 | *.tmp
64 | *.tmp_proj
65 | *.log
66 | *.vspscc
67 | *.vssscc
68 | .builds
69 | *.pidb
70 | *.svclog
71 | *.scc
72 |
73 | # Chutzpah Test files
74 | _Chutzpah*
75 |
76 | # Visual C++ cache files
77 | ipch/
78 | *.aps
79 | *.ncb
80 | *.opendb
81 | *.opensdf
82 | *.sdf
83 | *.cachefile
84 | *.VC.db
85 | *.VC.VC.opendb
86 |
87 | # Visual Studio profiler
88 | *.psess
89 | *.vsp
90 | *.vspx
91 | *.sap
92 |
93 | # TFS 2012 Local Workspace
94 | $tf/
95 |
96 | # Guidance Automation Toolkit
97 | *.gpState
98 |
99 | # ReSharper is a .NET coding add-in
100 | _ReSharper*/
101 | *.[Rr]e[Ss]harper
102 | *.DotSettings.user
103 |
104 | # JustCode is a .NET coding add-in
105 | .JustCode
106 |
107 | # TeamCity is a build add-in
108 | _TeamCity*
109 |
110 | # DotCover is a Code Coverage Tool
111 | *.dotCover
112 |
113 | # NCrunch
114 | _NCrunch_*
115 | .*crunch*.local.xml
116 | nCrunchTemp_*
117 |
118 | # MightyMoose
119 | *.mm.*
120 | AutoTest.Net/
121 |
122 | # Web workbench (sass)
123 | .sass-cache/
124 |
125 | # Installshield output folder
126 | [Ee]xpress/
127 |
128 | # DocProject is a documentation generator add-in
129 | DocProject/buildhelp/
130 | DocProject/Help/*.HxT
131 | DocProject/Help/*.HxC
132 | DocProject/Help/*.hhc
133 | DocProject/Help/*.hhk
134 | DocProject/Help/*.hhp
135 | DocProject/Help/Html2
136 | DocProject/Help/html
137 |
138 | # Click-Once directory
139 | publish/
140 |
141 | # Publish Web Output
142 | *.[Pp]ublish.xml
143 | *.azurePubxml
144 | # TODO: Comment the next line if you want to checkin your web deploy settings
145 | # but database connection strings (with potential passwords) will be unencrypted
146 | #*.pubxml
147 | *.publishproj
148 |
149 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
150 | # checkin your Azure Web App publish settings, but sensitive information contained
151 | # in these scripts will be unencrypted
152 | PublishScripts/
153 |
154 | # NuGet Packages
155 | # The packages folder can be ignored because of Package Restore
156 | **/packages/*
157 | # except build/, which is used as an MSBuild target.
158 | !**/packages/build/
159 | # Uncomment if necessary however generally it will be regenerated when needed
160 | #!**/packages/repositories.config
161 | # NuGet v3's project.json files produces more ignoreable files
162 | *.nuget.props
163 | *.nuget.targets
164 |
165 | # Microsoft Azure Build Output
166 | csx/
167 | *.build.csdef
168 |
169 | # Microsoft Azure Emulator
170 | ecf/
171 | rcf/
172 |
173 | # Windows Store app package directories and files
174 | AppPackages/
175 | BundleArtifacts/
176 | Package.StoreAssociation.xml
177 | _pkginfo.txt
178 |
179 | # Visual Studio cache files
180 | # files ending in .cache can be ignored
181 | *.[Cc]ache
182 | # but keep track of directories ending in .cache
183 | !*.[Cc]ache/
184 |
185 | # Others
186 | ClientBin/
187 | ~$*
188 | *~
189 | *.dbmdl
190 | *.dbproj.schemaview
191 | *.jfm
192 | *.publishsettings
193 | node_modules/
194 | orleans.codegen.cs
195 |
196 | # Since there are multiple workflows, uncomment next line to ignore bower_components
197 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
198 | #bower_components/
199 |
200 | # RIA/Silverlight projects
201 | Generated_Code/
202 |
203 | # Backup & report files from converting an old project file
204 | # to a newer Visual Studio version. Backup files are not needed,
205 | # because we have git ;-)
206 | _UpgradeReport_Files/
207 | Backup*/
208 | UpgradeLog*.XML
209 | UpgradeLog*.htm
210 |
211 | # SQL Server files
212 | *.mdf
213 | *.ldf
214 |
215 | # Business Intelligence projects
216 | *.rdl.data
217 | *.bim.layout
218 | *.bim_*.settings
219 |
220 | # Microsoft Fakes
221 | FakesAssemblies/
222 |
223 | # GhostDoc plugin setting file
224 | *.GhostDoc.xml
225 |
226 | # Node.js Tools for Visual Studio
227 | .ntvs_analysis.dat
228 |
229 | # Visual Studio 6 build log
230 | *.plg
231 |
232 | # Visual Studio 6 workspace options file
233 | *.opt
234 |
235 | # Visual Studio LightSwitch build output
236 | **/*.HTMLClient/GeneratedArtifacts
237 | **/*.DesktopClient/GeneratedArtifacts
238 | **/*.DesktopClient/ModelManifest.xml
239 | **/*.Server/GeneratedArtifacts
240 | **/*.Server/ModelManifest.xml
241 | _Pvt_Extensions
242 |
243 | # Paket dependency manager
244 | .paket/paket.exe
245 | paket-files/
246 |
247 | # FAKE - F# Make
248 | .fake/
249 |
250 | # JetBrains Rider
251 | .idea/
252 | *.sln.iml
253 |
254 | # CodeRush
255 | .cr/
256 |
257 | # Python Tools for Visual Studio (PTVS)
258 | __pycache__/
259 | *.pyc
260 |
261 | # Recognition Assets
262 | recognition-assets/
263 | INFO/
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | We gladly welcome pull requests. If you have any questions, or want help solving a problem, feel free to stop by the [#MyScript forum](https://developer.myscript.com/support/).
4 |
5 | ## License
6 |
7 | Those examples are licensed under the [Apache 2.0](https://opensource.org/license/apache-2-0).
8 |
--------------------------------------------------------------------------------
/Demo/App.xaml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Demo/App.xaml.cs:
--------------------------------------------------------------------------------
1 | // Copyright @ MyScript. All rights reserved.
2 |
3 | using System;
4 | using Windows.ApplicationModel;
5 | using Windows.ApplicationModel.Activation;
6 | using Windows.UI.Popups;
7 | using Windows.UI.Xaml;
8 | using Windows.UI.Xaml.Controls;
9 | using Windows.UI.Xaml.Navigation;
10 |
11 | namespace MyScript.IInk.Demo
12 | {
13 | sealed partial class App : Application
14 | {
15 | public static Engine Engine { get; private set; }
16 |
17 | public App()
18 | {
19 | InitializeComponent();
20 | Suspending += OnSuspending;
21 | UnhandledException += OnUnhandledException;
22 | }
23 |
24 | private static void Initialize(Engine engine)
25 | {
26 | // Folders "conf" and "resources" are currently parts of the layout
27 | // (for each conf/res file of the project => properties => "Build Action = content")
28 | var confDirs = new string[1];
29 | confDirs[0] = "conf";
30 | engine.Configuration.SetStringArray("configuration-manager.search-path", confDirs);
31 |
32 | var localFolder = Windows.Storage.ApplicationData.Current.LocalFolder.Path;
33 | var tempFolder = System.IO.Path.Combine(localFolder, "tmp");
34 | engine.Configuration.SetString("content-package.temp-folder", tempFolder);
35 |
36 | EnableStrokePrediction(engine, true, 16);
37 |
38 | // Configure multithreading for text recognition
39 | SetMaxRecognitionThreadCount(engine, 1);
40 | }
41 |
42 | private static void EnableStrokePrediction(Engine engine, bool enable, uint durationMs = 16)
43 | {
44 | engine.Configuration.SetBoolean("renderer.prediction.enable", enable);
45 | engine.Configuration.SetNumber("renderer.prediction.duration", durationMs);
46 | }
47 |
48 | private static void SetMaxRecognitionThreadCount(Engine engine, uint threadCount)
49 | {
50 | engine.Configuration.SetNumber("max-recognition-thread-count", threadCount);
51 | }
52 |
53 | private static async void OnUnhandledException(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e)
54 | {
55 | e.Handled = true;
56 | await ShowErrorDialog(e.Message);
57 | }
58 |
59 | private static async System.Threading.Tasks.Task ShowErrorDialog(string message)
60 | {
61 | var dialog = new MessageDialog("Error: " + message);
62 |
63 | dialog.Commands.Add(new UICommand("Abort", delegate
64 | {
65 | Current.Exit();
66 | }));
67 |
68 | await dialog.ShowAsync();
69 | return false;
70 | }
71 |
72 | protected override async void OnLaunched(LaunchActivatedEventArgs e)
73 | {
74 | var rootFrame = Window.Current.Content as Frame;
75 |
76 | try
77 | {
78 | // Initialize Interactive Ink runtime environment
79 | Initialize(Engine = Engine.Create((byte[])(Array)Certificate.MyCertificate.Bytes));
80 | }
81 | catch (Exception err)
82 | {
83 | await ShowErrorDialog(err.Message);
84 | }
85 |
86 | if (rootFrame == null)
87 | {
88 | rootFrame = new Frame();
89 |
90 | rootFrame.NavigationFailed += OnNavigationFailed;
91 |
92 | Window.Current.Content = rootFrame;
93 | }
94 |
95 | if (!e.PrelaunchActivated)
96 | {
97 | if (rootFrame.Content == null)
98 | {
99 | rootFrame.Navigate(typeof(MainPage), e.Arguments);
100 | }
101 |
102 | Window.Current.Activate();
103 | }
104 | }
105 |
106 | static void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
107 | {
108 | throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
109 | }
110 |
111 | private static void OnSuspending(object sender, SuspendingEventArgs e)
112 | {
113 | var deferral = e.SuspendingOperation.GetDeferral();
114 |
115 | deferral.Complete();
116 | }
117 | }
118 | }
119 |
--------------------------------------------------------------------------------
/Demo/Assets/LockScreenLogo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyScript/interactive-ink-examples-uwp/c100f83d8914347839529b1e88dac069d7d4a26a/Demo/Assets/LockScreenLogo.scale-200.png
--------------------------------------------------------------------------------
/Demo/Assets/SplashScreen.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyScript/interactive-ink-examples-uwp/c100f83d8914347839529b1e88dac069d7d4a26a/Demo/Assets/SplashScreen.scale-200.png
--------------------------------------------------------------------------------
/Demo/Assets/Square150x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyScript/interactive-ink-examples-uwp/c100f83d8914347839529b1e88dac069d7d4a26a/Demo/Assets/Square150x150Logo.scale-200.png
--------------------------------------------------------------------------------
/Demo/Assets/Square44x44Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyScript/interactive-ink-examples-uwp/c100f83d8914347839529b1e88dac069d7d4a26a/Demo/Assets/Square44x44Logo.scale-200.png
--------------------------------------------------------------------------------
/Demo/Assets/Square44x44Logo.targetsize-24_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyScript/interactive-ink-examples-uwp/c100f83d8914347839529b1e88dac069d7d4a26a/Demo/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
--------------------------------------------------------------------------------
/Demo/Assets/StoreLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyScript/interactive-ink-examples-uwp/c100f83d8914347839529b1e88dac069d7d4a26a/Demo/Assets/StoreLogo.png
--------------------------------------------------------------------------------
/Demo/Assets/Wide310x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyScript/interactive-ink-examples-uwp/c100f83d8914347839529b1e88dac069d7d4a26a/Demo/Assets/Wide310x150Logo.scale-200.png
--------------------------------------------------------------------------------
/Demo/MainPage.xaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
52 |
53 |
58 |
59 |
65 |
66 |
--------------------------------------------------------------------------------
/Demo/MyCertificate.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * MyCertificate.cs
3 | * Replace this file with with the one you received by mail when you registered
4 | * as a developer on https://developer.myscript.com.
5 | */
6 | namespace MyScript.Certificate
7 | {
8 | public sealed class MyCertificate
9 | {
10 | public static sbyte[] Bytes
11 | {
12 | get
13 | {
14 | throw new System.Exception("Please replace the content of MyCertificate.cs with the certificate you received from the developer portal");
15 | }
16 | }
17 |
18 | } // end of: class MyCertificate
19 |
20 | } // end of: namespace
21 |
--------------------------------------------------------------------------------
/Demo/MyScript.InteractiveInk.Demo.Uwp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | obj
6 | bin
7 |
8 |
9 |
10 | Debug
11 | x64
12 | {785F77C0-DF74-4F40-AB84-8AAFCEDF2619}
13 | AppContainerExe
14 | Properties
15 | MyScript.IInk.Demo
16 | MyScript.InteractiveInk.Demo.Uwp
17 | en-US
18 | UAP
19 | 10.0.22621.0
20 | 10.0.17763.0
21 | 14
22 | 512
23 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
24 | true
25 | MyScript.InteractiveInk.Demo.Uwp_TemporaryKey.pfx
26 | False
27 | Never
28 | x64
29 | True
30 |
31 |
32 |
33 | 6.2.13
34 |
35 |
36 |
37 | true
38 | $(BaseOutputPath)\$(Platform)\$(Configuration)\
39 | $(BaseIntermediateOutputPath)\$(Platform)\$(Configuration)\
40 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
41 | ;2008
42 | full
43 | x64
44 | false
45 | prompt
46 | true
47 |
48 |
49 | $(BaseOutputPath)\$(Platform)\$(Configuration)\
50 | $(BaseIntermediateOutputPath)\$(Platform)\$(Configuration)\
51 | TRACE;NETFX_CORE;WINDOWS_UWP
52 | true
53 | ;2008
54 | pdbonly
55 | x64
56 | false
57 | prompt
58 | true
59 | true
60 |
61 |
62 | PackageReference
63 |
64 |
65 |
66 | App.xaml
67 |
68 |
69 | MainPage.xaml
70 |
71 |
72 |
73 |
74 |
75 |
76 | Designer
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 | configurations\%(RecursiveDir)%(FileName)%(Extension)
92 |
93 |
94 | conf\diagram.conf
95 |
96 |
97 | conf\raw-content.conf
98 |
99 |
100 | conf\raw-content2.conf
101 |
102 |
103 | conf\en_US.conf
104 |
105 |
106 | conf\math.conf
107 |
108 |
109 | conf\math2.conf
110 |
111 |
112 | fonts\MyScriptInter-Bold.otf
113 |
114 |
115 | fonts\MyScriptInter-Regular.otf
116 |
117 |
118 | fonts\STIXTwoText-Italic.otf
119 |
120 |
121 | fonts\STIXTwoMath-Regular.otf
122 |
123 |
124 | resources\analyzer\ank-diagram.res
125 |
126 |
127 | resources\analyzer\ank-raw-content.res
128 |
129 |
130 | resources\document_layout\dl-raw-content.res
131 |
132 |
133 | resources\en_US\en_US-ak-cur.res
134 |
135 |
136 | resources\en_US\en_US-lk-text.res
137 |
138 |
139 | resources\math\math-ak.res
140 |
141 |
142 | resources\math\math-grm-standard.res
143 |
144 |
145 | resources\math\math-sr.res
146 |
147 |
148 | resources\shape\shk-diagram.res
149 |
150 |
151 |
152 |
153 | MSBuild:Compile
154 | Designer
155 |
156 |
157 | MSBuild:Compile
158 | Designer
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 | {667892f3-1761-4ea9-bdfa-71944c768bad}
167 | MyScript.InteractiveInk.UIReferenceImplementation.Uwp
168 |
169 |
170 |
171 | 15.0
172 |
173 |
174 |
175 | powershell.exe -NonInteractive -executionpolicy unrestricted -File "$(SolutionDir)getRecognitionAssets.ps1"
176 |
177 |
184 |
--------------------------------------------------------------------------------
/Demo/MyScript.InteractiveInk.Demo.Uwp_TemporaryKey.pfx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyScript/interactive-ink-examples-uwp/c100f83d8914347839529b1e88dac069d7d4a26a/Demo/MyScript.InteractiveInk.Demo.Uwp_TemporaryKey.pfx
--------------------------------------------------------------------------------
/Demo/Package.appxmanifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | iink Demo
7 | MyScript
8 | Assets\StoreLogo.png
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Demo/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("MyScript.InteractiveInk.Demo.Uwp")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("MyScript")]
12 | [assembly: AssemblyProduct("MyScript.InteractiveInk.Demo.Uwp")]
13 | [assembly: AssemblyCopyright("Copyright @ MyScript. All rights reserved.")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Version information for an assembly consists of the following four values:
18 | //
19 | // Major Version
20 | // Minor Version
21 | // Build Number
22 | // Revision
23 | //
24 | // You can specify all the values or you can default the Build and Revision Numbers
25 | // by using the '*' as shown below:
26 | // [assembly: AssemblyVersion("1.0.*")]
27 | [assembly: AssemblyVersion("4.1.0.0")]
28 | [assembly: AssemblyFileVersion("4.1.0.0")]
29 | [assembly: ComVisible(false)]
30 |
--------------------------------------------------------------------------------
/Demo/Properties/Default.rd.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/GetStarted/App.xaml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
--------------------------------------------------------------------------------
/GetStarted/App.xaml.cs:
--------------------------------------------------------------------------------
1 | // Copyright @ MyScript. All rights reserved.
2 |
3 | using System;
4 | using Windows.ApplicationModel;
5 | using Windows.ApplicationModel.Activation;
6 | using Windows.UI.Popups;
7 | using Windows.UI.Xaml;
8 | using Windows.UI.Xaml.Controls;
9 | using Windows.UI.Xaml.Navigation;
10 |
11 | namespace MyScript.IInk.GetStarted
12 | {
13 | sealed partial class App : Application
14 | {
15 | public static Engine Engine { get; private set; }
16 |
17 | public App()
18 | {
19 | InitializeComponent();
20 | Suspending += OnSuspending;
21 | UnhandledException += OnUnhandledException;
22 | }
23 |
24 | private static void Initialize(Engine engine)
25 | {
26 | // Folders "conf" and "resources" are currently parts of the layout
27 | // (for each conf/res file of the project => properties => "Build Action = content")
28 | var confDirs = new string[1];
29 | confDirs[0] = "conf";
30 | engine.Configuration.SetStringArray("configuration-manager.search-path", confDirs);
31 |
32 | var localFolder = Windows.Storage.ApplicationData.Current.LocalFolder.Path;
33 | var tempFolder = System.IO.Path.Combine(localFolder, "tmp");
34 | engine.Configuration.SetString("content-package.temp-folder", tempFolder);
35 | }
36 |
37 | private async void OnUnhandledException(object sender, Windows.UI.Xaml.UnhandledExceptionEventArgs e)
38 | {
39 | e.Handled = true;
40 | await ShowErrorDialog(e.Message);
41 | }
42 |
43 | private async System.Threading.Tasks.Task ShowErrorDialog(string message)
44 | {
45 | var dialog = new MessageDialog("Error: " + message);
46 |
47 | dialog.Commands.Add(new UICommand("Abort", delegate (IUICommand command)
48 | {
49 | Current.Exit();
50 | }));
51 |
52 | await dialog.ShowAsync();
53 | return false;
54 | }
55 |
56 | protected override async void OnLaunched(LaunchActivatedEventArgs e)
57 | {
58 | var rootFrame = Window.Current.Content as Frame;
59 |
60 | try
61 | {
62 | // Initialize Interactive Ink runtime environment
63 | Initialize(Engine = Engine.Create((byte[])(Array)Certificate.MyCertificate.Bytes));
64 | }
65 | catch (Exception err)
66 | {
67 | await ShowErrorDialog(err.Message);
68 | }
69 |
70 | if (rootFrame == null)
71 | {
72 | rootFrame = new Frame();
73 |
74 | rootFrame.NavigationFailed += OnNavigationFailed;
75 |
76 | if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
77 | {
78 | }
79 |
80 | Window.Current.Content = rootFrame;
81 | }
82 |
83 | if (e.PrelaunchActivated == false)
84 | {
85 | if (rootFrame.Content == null)
86 | {
87 | rootFrame.Navigate(typeof(MainPage), e.Arguments);
88 | }
89 |
90 | Window.Current.Activate();
91 | }
92 | }
93 |
94 | void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
95 | {
96 | throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
97 | }
98 |
99 | private void OnSuspending(object sender, SuspendingEventArgs e)
100 | {
101 | var deferral = e.SuspendingOperation.GetDeferral();
102 | deferral.Complete();
103 | }
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/GetStarted/Assets/LockScreenLogo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyScript/interactive-ink-examples-uwp/c100f83d8914347839529b1e88dac069d7d4a26a/GetStarted/Assets/LockScreenLogo.scale-200.png
--------------------------------------------------------------------------------
/GetStarted/Assets/SplashScreen.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyScript/interactive-ink-examples-uwp/c100f83d8914347839529b1e88dac069d7d4a26a/GetStarted/Assets/SplashScreen.scale-200.png
--------------------------------------------------------------------------------
/GetStarted/Assets/Square150x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyScript/interactive-ink-examples-uwp/c100f83d8914347839529b1e88dac069d7d4a26a/GetStarted/Assets/Square150x150Logo.scale-200.png
--------------------------------------------------------------------------------
/GetStarted/Assets/Square44x44Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyScript/interactive-ink-examples-uwp/c100f83d8914347839529b1e88dac069d7d4a26a/GetStarted/Assets/Square44x44Logo.scale-200.png
--------------------------------------------------------------------------------
/GetStarted/Assets/Square44x44Logo.targetsize-24_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyScript/interactive-ink-examples-uwp/c100f83d8914347839529b1e88dac069d7d4a26a/GetStarted/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
--------------------------------------------------------------------------------
/GetStarted/Assets/StoreLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyScript/interactive-ink-examples-uwp/c100f83d8914347839529b1e88dac069d7d4a26a/GetStarted/Assets/StoreLogo.png
--------------------------------------------------------------------------------
/GetStarted/Assets/Wide310x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyScript/interactive-ink-examples-uwp/c100f83d8914347839529b1e88dac069d7d4a26a/GetStarted/Assets/Wide310x150Logo.scale-200.png
--------------------------------------------------------------------------------
/GetStarted/MainPage.xaml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
29 |
34 |
37 |
39 |
41 |
42 |
43 |
--------------------------------------------------------------------------------
/GetStarted/MainPage.xaml.cs:
--------------------------------------------------------------------------------
1 | // Copyright @ MyScript. All rights reserved.
2 |
3 | using System;
4 | using System.Linq;
5 | using Windows.Graphics.Display;
6 | using Windows.UI.Xaml;
7 | using MyScript.IInk.UIReferenceImplementation;
8 |
9 | namespace MyScript.IInk.GetStarted
10 | {
11 | public sealed partial class MainPage
12 | {
13 | public static readonly DependencyProperty EditorProperty =
14 | DependencyProperty.Register("Editor", typeof(Editor), typeof(MainPage),
15 | new PropertyMetadata(default(Editor)));
16 |
17 | public Editor Editor
18 | {
19 | get => GetValue(EditorProperty) as Editor;
20 | set => SetValue(EditorProperty, value);
21 | }
22 | }
23 |
24 | public sealed partial class MainPage
25 | {
26 | // Offscreen rendering
27 | private float _dpiX = 96;
28 | private float _dpiY = 96;
29 |
30 | // Defines the type of content (possible values are: "Text Document", "Text", "Diagram", "Math", "Drawing" and "Raw Content")
31 | private const string PartType = "Text Document";
32 |
33 | public MainPage()
34 | {
35 | InitializeComponent();
36 | Initialize(App.Engine);
37 | }
38 |
39 | private void Initialize(Engine engine)
40 | {
41 | // Initialize the editor with the engine
42 | var info = DisplayInformation.GetForCurrentView();
43 | _dpiX = info.RawDpiX;
44 | _dpiY = info.RawDpiY;
45 | var pixelDensity = UcEditor.GetPixelDensity();
46 |
47 | if (pixelDensity > 0.0f)
48 | {
49 | _dpiX /= pixelDensity;
50 | _dpiY /= pixelDensity;
51 | }
52 |
53 | // RawDpi properties can return 0 when the monitor does not provide physical dimensions and when the user is
54 | // in a clone or duplicate multiple -monitor setup.
55 | if (_dpiX == 0 || _dpiY == 0)
56 | _dpiX = _dpiY = 96;
57 |
58 | var renderer = engine.CreateRenderer(_dpiX, _dpiY, UcEditor);
59 | renderer.AddListener(new RendererListener(UcEditor));
60 | var toolController = engine.CreateToolController();
61 | Initialize(Editor = engine.CreateEditor(renderer, toolController));
62 | Initialize(Editor.ToolController);
63 |
64 | NewFile();
65 | }
66 |
67 | private void Initialize(Editor editor)
68 | {
69 | editor.SetViewSize((int)ActualWidth, (int)ActualHeight);
70 | editor.SetFontMetricsProvider(new FontMetricsProvider(_dpiX, _dpiY));
71 | editor.AddListener(new EditorListener(UcEditor));
72 | }
73 |
74 | private static void Initialize(ToolController controller)
75 | {
76 | controller.SetToolForType(PointerType.MOUSE, PointerTool.PEN);
77 | controller.SetToolForType(PointerType.PEN, PointerTool.PEN);
78 | controller.SetToolForType(PointerType.TOUCH, PointerTool.PEN);
79 | }
80 |
81 | private void AppBar_UndoButton_Click(object sender, RoutedEventArgs e)
82 | {
83 | Editor.Undo();
84 | }
85 |
86 | private void AppBar_RedoButton_Click(object sender, RoutedEventArgs e)
87 | {
88 | Editor.Redo();
89 | }
90 |
91 | private void AppBar_ClearButton_Click(object sender, RoutedEventArgs e)
92 | {
93 | Editor.Clear();
94 | }
95 |
96 | private async void AppBar_ConvertButton_Click(object sender, RoutedEventArgs e)
97 | {
98 | try
99 | {
100 | var supportedStates = Editor.GetSupportedTargetConversionStates(null);
101 |
102 | if ( (supportedStates != null) && (supportedStates.Count() > 0) )
103 | Editor.Convert(null, supportedStates[0]);
104 | }
105 | catch (Exception ex)
106 | {
107 | var msgDialog = new Windows.UI.Popups.MessageDialog(ex.ToString());
108 | await msgDialog.ShowAsync();
109 | }
110 | }
111 |
112 | private void ClosePackage()
113 | {
114 | var part = Editor.Part;
115 | var package = part?.Package;
116 | Editor.Part = null;
117 | part?.Dispose();
118 | package?.Dispose();
119 | Title.Text = "";
120 | }
121 |
122 | private async void NewFile()
123 | {
124 | try
125 | {
126 | // Close current package
127 | ClosePackage();
128 |
129 | // Create package and part
130 | var packageName = MakeUntitledFilename();
131 | var package = Editor.Engine.CreatePackage(packageName);
132 | var part = package.CreatePart(PartType);
133 | Editor.Part = part;
134 | Title.Text = "Type: " + PartType;
135 | }
136 | catch (Exception ex)
137 | {
138 | ClosePackage();
139 |
140 | var msgDialog = new Windows.UI.Popups.MessageDialog(ex.ToString());
141 | await msgDialog.ShowAsync();
142 | Application.Current.Exit();
143 | }
144 | }
145 |
146 | private static string MakeUntitledFilename()
147 | {
148 | var localFolder = Windows.Storage.ApplicationData.Current.LocalFolder.Path;
149 | var num = 0;
150 | string name;
151 |
152 | do
153 | {
154 | var baseName = "File" + (++num) + ".iink";
155 | name = System.IO.Path.Combine(localFolder, baseName);
156 | }
157 | while (System.IO.File.Exists(name));
158 |
159 | return name;
160 | }
161 |
162 | private void OnPenClick(object sender, RoutedEventArgs e)
163 | {
164 | if (!(Editor?.ToolController is ToolController controller)) return;
165 | controller.SetToolForType(PointerType.MOUSE, PointerTool.PEN);
166 | controller.SetToolForType(PointerType.PEN, PointerTool.PEN);
167 | controller.SetToolForType(PointerType.TOUCH, PointerTool.PEN);
168 | }
169 |
170 | private void OnTouchClick(object sender, RoutedEventArgs e)
171 | {
172 | if (!(Editor?.ToolController is ToolController controller)) return;
173 | controller.SetToolForType(PointerType.MOUSE, PointerTool.HAND);
174 | controller.SetToolForType(PointerType.PEN, PointerTool.HAND);
175 | controller.SetToolForType(PointerType.TOUCH, PointerTool.HAND);
176 | }
177 |
178 | private void OnAutoClick(object sender, RoutedEventArgs e)
179 | {
180 | if (!(Editor?.ToolController is ToolController controller)) return;
181 | controller.SetToolForType(PointerType.MOUSE, PointerTool.PEN);
182 | controller.SetToolForType(PointerType.PEN, PointerTool.HAND);
183 | controller.SetToolForType(PointerType.TOUCH, PointerTool.PEN);
184 | }
185 | }
186 | }
187 |
--------------------------------------------------------------------------------
/GetStarted/MyCertificate.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * MyCertificate.cs
3 | * Replace this file with with the one you received by mail when you registered
4 | * as a developer on https://developer.myscript.com.
5 | */
6 | namespace MyScript.Certificate
7 | {
8 | public sealed class MyCertificate
9 | {
10 | public static sbyte[] Bytes
11 | {
12 | get
13 | {
14 | throw new System.Exception("Please replace the content of MyCertificate.cs with the certificate you received from the developer portal");
15 | }
16 | }
17 |
18 | } // end of: class MyCertificate
19 |
20 | } // end of: namespace
21 |
--------------------------------------------------------------------------------
/GetStarted/MyScript.InteractiveInk.GetStarted.Uwp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | obj
6 | bin
7 |
8 |
9 |
10 | Debug
11 | x64
12 | {01436395-FD36-494A-87F9-FD0EF5B033FF}
13 | AppContainerExe
14 | Properties
15 | MyScript.IInk.GetStarted
16 | MyScript.InteractiveInk.GetStarted.Uwp
17 | en-US
18 | UAP
19 | 10.0.22621.0
20 | 10.0.17763.0
21 | 14
22 | 512
23 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
24 | true
25 | MyScript.InteractiveInk.GetStarted.Uwp_TemporaryKey.pfx
26 | False
27 | Never
28 | True
29 |
30 |
31 |
32 | 6.2.13
33 |
34 |
35 |
36 | true
37 | $(BaseOutputPath)\$(Platform)\$(Configuration)\
38 | $(BaseIntermediateOutputPath)\$(Platform)\$(Configuration)\
39 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
40 | ;2008
41 | full
42 | x64
43 | false
44 | prompt
45 | true
46 |
47 |
48 | $(BaseOutputPath)\$(Platform)\$(Configuration)\
49 | $(BaseIntermediateOutputPath)\$(Platform)\$(Configuration)\
50 | TRACE;NETFX_CORE;WINDOWS_UWP
51 | true
52 | ;2008
53 | pdbonly
54 | x64
55 | false
56 | prompt
57 | true
58 | true
59 |
60 |
61 | PackageReference
62 |
63 |
64 |
65 | App.xaml
66 |
67 |
68 | MainPage.xaml
69 |
70 |
71 |
72 |
73 |
74 |
75 | Designer
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 | conf\diagram.conf
91 |
92 |
93 | conf\raw-content.conf
94 |
95 |
96 | conf\raw-content2.conf
97 |
98 |
99 | conf\en_US.conf
100 |
101 |
102 | conf\math.conf
103 |
104 |
105 | conf\math2.conf
106 |
107 |
108 | resources\analyzer\ank-diagram.res
109 |
110 |
111 | resources\analyzer\ank-raw-content.res
112 |
113 |
114 | resources\document_layout\dl-raw-content.res
115 |
116 |
117 | resources\en_US\en_US-ak-cur.res
118 |
119 |
120 | resources\en_US\en_US-lk-text.res
121 |
122 |
123 | resources\math\math-ak.res
124 |
125 |
126 | resources\math\math-grm-standard.res
127 |
128 |
129 | resources\math\math-sr.res
130 |
131 |
132 | resources\shape\shk-diagram.res
133 |
134 |
135 |
136 |
137 | MSBuild:Compile
138 | Designer
139 |
140 |
141 | MSBuild:Compile
142 | Designer
143 |
144 |
145 |
146 |
147 | {667892f3-1761-4ea9-bdfa-71944c768bad}
148 | MyScript.InteractiveInk.UIReferenceImplementation.Uwp
149 |
150 |
151 |
152 |
153 |
154 |
155 | 15.0
156 |
157 |
158 |
159 | powershell.exe -NonInteractive -executionpolicy unrestricted -File "$(SolutionDir)getRecognitionAssets.ps1"
160 |
161 |
168 |
--------------------------------------------------------------------------------
/GetStarted/MyScript.InteractiveInk.GetStarted.Uwp_TemporaryKey.pfx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyScript/interactive-ink-examples-uwp/c100f83d8914347839529b1e88dac069d7d4a26a/GetStarted/MyScript.InteractiveInk.GetStarted.Uwp_TemporaryKey.pfx
--------------------------------------------------------------------------------
/GetStarted/Package.appxmanifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | iink GetStarted
7 | MyScript
8 | Assets\StoreLogo.png
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/GetStarted/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("MyScript.InteractiveInk.GetStarted.Uwp")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("MyScript")]
12 | [assembly: AssemblyProduct("MyScript.InteractiveInk.GetStarted.Uwp")]
13 | [assembly: AssemblyCopyright("Copyright @ MyScript. All rights reserved.")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Version information for an assembly consists of the following four values:
18 | //
19 | // Major Version
20 | // Minor Version
21 | // Build Number
22 | // Revision
23 | //
24 | // You can specify all the values or you can default the Build and Revision Numbers
25 | // by using the '*' as shown below:
26 | // [assembly: AssemblyVersion("1.0.*")]
27 | [assembly: AssemblyVersion("4.1.0.0")]
28 | [assembly: AssemblyFileVersion("4.1.0.0")]
29 | [assembly: ComVisible(false)]
30 |
--------------------------------------------------------------------------------
/GetStarted/Properties/Default.rd.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/LICENSES/inter.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016-2020 The Inter Project Authors.
2 | "Inter" is trademark of Rasmus Andersson.
3 | https://github.com/rsms/inter
4 |
5 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
6 | This license is copied below, and is also available with a FAQ at:
7 | http://scripts.sil.org/OFL
8 |
9 | -----------------------------------------------------------
10 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
11 | -----------------------------------------------------------
12 |
13 | PREAMBLE
14 | The goals of the Open Font License (OFL) are to stimulate worldwide
15 | development of collaborative font projects, to support the font creation
16 | efforts of academic and linguistic communities, and to provide a free and
17 | open framework in which fonts may be shared and improved in partnership
18 | with others.
19 |
20 | The OFL allows the licensed fonts to be used, studied, modified and
21 | redistributed freely as long as they are not sold by themselves. The
22 | fonts, including any derivative works, can be bundled, embedded,
23 | redistributed and/or sold with any software provided that any reserved
24 | names are not used by derivative works. The fonts and derivatives,
25 | however, cannot be released under any other type of license. The
26 | requirement for fonts to remain under this license does not apply
27 | to any document created using the fonts or their derivatives.
28 |
29 | DEFINITIONS
30 | "Font Software" refers to the set of files released by the Copyright
31 | Holder(s) under this license and clearly marked as such. This may
32 | include source files, build scripts and documentation.
33 |
34 | "Reserved Font Name" refers to any names specified as such after the
35 | copyright statement(s).
36 |
37 | "Original Version" refers to the collection of Font Software components as
38 | distributed by the Copyright Holder(s).
39 |
40 | "Modified Version" refers to any derivative made by adding to, deleting,
41 | or substituting -- in part or in whole -- any of the components of the
42 | Original Version, by changing formats or by porting the Font Software to a
43 | new environment.
44 |
45 | "Author" refers to any designer, engineer, programmer, technical
46 | writer or other person who contributed to the Font Software.
47 |
48 | PERMISSION AND CONDITIONS
49 | Permission is hereby granted, free of charge, to any person obtaining
50 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
51 | redistribute, and sell modified and unmodified copies of the Font
52 | Software, subject to the following conditions:
53 |
54 | 1) Neither the Font Software nor any of its individual components,
55 | in Original or Modified Versions, may be sold by itself.
56 |
57 | 2) Original or Modified Versions of the Font Software may be bundled,
58 | redistributed and/or sold with any software, provided that each copy
59 | contains the above copyright notice and this license. These can be
60 | included either as stand-alone text files, human-readable headers or
61 | in the appropriate machine-readable metadata fields within text or
62 | binary files as long as those fields can be easily viewed by the user.
63 |
64 | 3) No Modified Version of the Font Software may use the Reserved Font
65 | Name(s) unless explicit written permission is granted by the corresponding
66 | Copyright Holder. This restriction only applies to the primary font name as
67 | presented to the users.
68 |
69 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
70 | Software shall not be used to promote, endorse or advertise any
71 | Modified Version, except to acknowledge the contribution(s) of the
72 | Copyright Holder(s) and the Author(s) or with their explicit written
73 | permission.
74 |
75 | 5) The Font Software, modified or unmodified, in part or in whole,
76 | must be distributed entirely under this license, and must not be
77 | distributed under any other license. The requirement for fonts to
78 | remain under this license does not apply to any document created
79 | using the Font Software.
80 |
81 | TERMINATION
82 | This license becomes null and void if any of the above conditions are
83 | not met.
84 |
85 | DISCLAIMER
86 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
87 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
88 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
89 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
90 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
91 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
92 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
93 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
94 | OTHER DEALINGS IN THE FONT SOFTWARE.
--------------------------------------------------------------------------------
/LICENSES/stix.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyScript/interactive-ink-examples-uwp/c100f83d8914347839529b1e88dac069d7d4a26a/LICENSES/stix.pdf
--------------------------------------------------------------------------------
/MyScript.InteractiveInk.Examples.Uwp.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 17
4 | VisualStudioVersion = 17.6.33723.286
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyScript.InteractiveInk.GetStarted.Uwp", "GetStarted\MyScript.InteractiveInk.GetStarted.Uwp.csproj", "{01436395-FD36-494A-87F9-FD0EF5B033FF}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyScript.InteractiveInk.UIReferenceImplementation.Uwp", "UIReferenceImplementation\MyScript.InteractiveInk.UIReferenceImplementation.Uwp.csproj", "{667892F3-1761-4EA9-BDFA-71944C768BAD}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyScript.InteractiveInk.Demo.Uwp", "Demo\MyScript.InteractiveInk.Demo.Uwp.csproj", "{785F77C0-DF74-4F40-AB84-8AAFCEDF2619}"
11 | EndProject
12 | Global
13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
14 | Debug|x64 = Debug|x64
15 | Release|x64 = Release|x64
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {01436395-FD36-494A-87F9-FD0EF5B033FF}.Debug|x64.ActiveCfg = Debug|x64
19 | {01436395-FD36-494A-87F9-FD0EF5B033FF}.Debug|x64.Build.0 = Debug|x64
20 | {01436395-FD36-494A-87F9-FD0EF5B033FF}.Debug|x64.Deploy.0 = Debug|x64
21 | {01436395-FD36-494A-87F9-FD0EF5B033FF}.Release|x64.ActiveCfg = Release|x64
22 | {01436395-FD36-494A-87F9-FD0EF5B033FF}.Release|x64.Build.0 = Release|x64
23 | {01436395-FD36-494A-87F9-FD0EF5B033FF}.Release|x64.Deploy.0 = Release|x64
24 | {667892F3-1761-4EA9-BDFA-71944C768BAD}.Debug|x64.ActiveCfg = Debug|x64
25 | {667892F3-1761-4EA9-BDFA-71944C768BAD}.Debug|x64.Build.0 = Debug|x64
26 | {667892F3-1761-4EA9-BDFA-71944C768BAD}.Release|x64.ActiveCfg = Release|x64
27 | {667892F3-1761-4EA9-BDFA-71944C768BAD}.Release|x64.Build.0 = Release|x64
28 | {785F77C0-DF74-4F40-AB84-8AAFCEDF2619}.Debug|x64.ActiveCfg = Debug|x64
29 | {785F77C0-DF74-4F40-AB84-8AAFCEDF2619}.Debug|x64.Build.0 = Debug|x64
30 | {785F77C0-DF74-4F40-AB84-8AAFCEDF2619}.Debug|x64.Deploy.0 = Debug|x64
31 | {785F77C0-DF74-4F40-AB84-8AAFCEDF2619}.Release|x64.ActiveCfg = Release|x64
32 | {785F77C0-DF74-4F40-AB84-8AAFCEDF2619}.Release|x64.Build.0 = Release|x64
33 | {785F77C0-DF74-4F40-AB84-8AAFCEDF2619}.Release|x64.Deploy.0 = Release|x64
34 | EndGlobalSection
35 | GlobalSection(SolutionProperties) = preSolution
36 | HideSolutionNode = FALSE
37 | EndGlobalSection
38 | GlobalSection(ExtensibilityGlobals) = postSolution
39 | SolutionGuid = {B3499168-F628-4339-9491-AFFC7FC82E02}
40 | EndGlobalSection
41 | EndGlobal
42 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## What is it about?
2 |
3 | Interactive Ink SDK is the best way to integrate handwriting recognition capabilities into your UWP application. Interactive Ink extends digital ink to allow users to more intuitively create, interact with, and share content in digital form. Handwritten text, mathematical equations or even diagrams are interpreted in real-time to be editable via simple gestures, responsive and easy to convert to a neat output.
4 |
5 | This repository contains a "get started" example, a complete example and a reference implementation of the UWP integration part that developers using Interactive Ink SDK can reuse inside their projects. All of those are written in C# and XAML.
6 |
7 | The repository content targets UWP platform.
8 |
9 | ## Getting started
10 |
11 | ### Installation
12 |
13 | 1. Clone the examples repository `git clone https://github.com/MyScript/interactive-ink-examples-uwp.git`
14 |
15 | 2. Claim a certificate to receive the free license to start develop your application by following the first steps of [Getting Started](https://developer.myscript.com/getting-started)
16 |
17 | 3. Copy this certificate to `GetStarted\MyCertificate.cs` and `Demo\MyCertificate.cs`
18 |
19 | 4. Open `MyScript.InteractiveInk.Examples.Uwp.sln` file. `GetStarted` project is the most simple example and is design to help you understand what Interactive Ink is about and how easy it is to integrate it into your application. `Demo` project contains a complete example and helps you build your own integration. You can select which project to launch by right-clicking the project in the solution browser and selecting "Set as startup project".
20 |
21 | ## Building your own integration
22 |
23 | In your application add the dependency to `MyScript.InteractiveInk.Uwp` nuget. Also copy `UIReferenceImplementation` directory into your project. More details available in the [developer guide](https://developer.myscript.com/docs/interactive-ink/latest/windows/).
24 |
25 | ## Documentation
26 |
27 | A complete guide is available on [MyScript Developer website](https://developer.myscript.com/docs/interactive-ink/latest/windows/).
28 |
29 | The API Reference is available in Visual Studio as soon as the Nugets packages are downloaded.
30 |
31 | ## Getting support
32 |
33 | You can get some support from the dedicated section on [MyScript Developer website](https://devportal.corp.myscript.com/support/).
34 |
35 | ## Sharing your feedback ?
36 |
37 | Made a cool app with Interactive Ink? Ready to cross join our marketing efforts? We would love to hear about you!
38 | We’re planning to showcase apps using it so let us know by sending a quick mail to [myapp@myscript.com](mailto://myapp@myscript.com).
39 |
--------------------------------------------------------------------------------
/UIReferenceImplementation/Canvas.cs:
--------------------------------------------------------------------------------
1 | // Copyright @ MyScript. All rights reserved.
2 |
3 | using MyScript.IInk.Graphics;
4 | using MyScript.IInk.UIReferenceImplementation.UserControls;
5 | using Microsoft.Graphics.Canvas;
6 | using Microsoft.Graphics.Canvas.Geometry;
7 | using Microsoft.Graphics.Canvas.Text;
8 | using System;
9 | using System.Numerics;
10 | using System.Collections.Generic;
11 | using Windows.Foundation;
12 | using MyScript.IInk.UIReferenceImplementation.Extensions;
13 |
14 | namespace MyScript.IInk.UIReferenceImplementation
15 | {
16 | public class Canvas : ICanvas
17 | {
18 | private CanvasDrawingSession _session;
19 | private IRenderTarget _target;
20 | private ImageLoader _imageLoader;
21 |
22 | private Transform _transform;
23 | private float _strokeWidth { get; set; }
24 | private Windows.UI.Color _strokeColor { get; set; }
25 | private CanvasStrokeStyle _strokeStyle { get; set; }
26 | private Windows.UI.Color _fillColor { get; set; }
27 | private CanvasFilledRegionDetermination _fillRule { get; set; }
28 | private CanvasTextFormat _fontProperties { get; set; }
29 | private Dictionary _layers;
30 | private float _baseline;
31 |
32 | private CanvasActiveLayer _activeLayer;
33 | private Rect _activeLayerRect;
34 |
35 | #region Privates (Drop Shadow)
36 |
37 | private float _dropShadowOffsetX = 0.5f;
38 | private float _dropShadowOffsetY = 0.5f;
39 | private float _dropShadowRadius = 2.0f;
40 | private Windows.UI.Color _dropShadowColor = default(Windows.UI.Color);
41 |
42 | #endregion
43 |
44 | public bool ClearOnStartDraw { get; set; } = true;
45 |
46 | public Canvas(CanvasDrawingSession session, IRenderTarget target, ImageLoader imageLoader)
47 | {
48 | _session = session;
49 | _target = target;
50 | _imageLoader = imageLoader;
51 |
52 | _transform = new Transform(1, 0, 0, 0, 1, 0);
53 |
54 | _strokeWidth = 1.0f;
55 | _strokeColor = Windows.UI.Colors.Transparent;
56 |
57 | _strokeStyle = new CanvasStrokeStyle
58 | {
59 | StartCap = CanvasCapStyle.Flat,
60 | EndCap = CanvasCapStyle.Flat,
61 | DashCap = CanvasCapStyle.Flat,
62 | LineJoin = CanvasLineJoin.Miter
63 | };
64 |
65 | _fillColor = Windows.UI.Colors.Black;
66 | _fillRule = CanvasFilledRegionDetermination.Winding;
67 |
68 | _fontProperties = new CanvasTextFormat
69 | {
70 | FontStyle = Windows.UI.Text.FontStyle.Normal,
71 | FontWeight = Windows.UI.Text.FontWeights.Normal,
72 | WordWrapping = CanvasWordWrapping.NoWrap,
73 | Options = FontMetricsProvider.UseColorFont ? CanvasDrawTextOptions.EnableColorFont : CanvasDrawTextOptions.Default
74 | };
75 |
76 | _baseline = 1.0f;
77 |
78 | _layers = new Dictionary();
79 | _activeLayer = null;
80 | _activeLayerRect = Rect.Empty;
81 | }
82 |
83 | public void DisposeSession()
84 | {
85 | if (_session != null)
86 | {
87 | _session.Dispose();
88 | _session = null;
89 | }
90 | }
91 |
92 | public void Begin()
93 | {
94 | _session.Antialiasing = CanvasAntialiasing.Antialiased;
95 | _session.TextAntialiasing = CanvasTextAntialiasing.Auto;
96 |
97 | var defaultStyle = new Style();
98 | defaultStyle.SetChangeFlags((uint)StyleFlag.StyleFlag_ALL);
99 | defaultStyle.ApplyTo(this);
100 | }
101 |
102 | public void End()
103 | {
104 | }
105 |
106 | public void Clear(Color color)
107 | {
108 | var color_ = Windows.UI.Color.FromArgb((byte)color.A, (byte)color.R, (byte)color.G, (byte)color.B);
109 | _session.Clear(color_);
110 | }
111 |
112 | public Transform Transform
113 | {
114 | get { return _transform; }
115 | set
116 | {
117 | var prevTr = new Transform(_transform);
118 | _transform = value;
119 | _session.Transform = new Matrix3x2((float)Transform.XX, (float)Transform.XY,
120 | (float)Transform.YX, (float)Transform.YY,
121 | (float)Transform.TX, (float)Transform.TY);
122 | // Update clipping, if any
123 | if (_activeLayer != null)
124 | {
125 | var invTransform = new Transform(_transform);
126 | invTransform.Invert();
127 | invTransform.Multiply(prevTr);
128 |
129 | var corners = new Graphics.Point[4];
130 | corners[0] = invTransform.Apply((float)_activeLayerRect.Left, (float)_activeLayerRect.Top);
131 | corners[1] = invTransform.Apply((float)_activeLayerRect.Right, (float)_activeLayerRect.Top);
132 | corners[2] = invTransform.Apply((float)_activeLayerRect.Right, (float)_activeLayerRect.Bottom);
133 | corners[3] = invTransform.Apply((float)_activeLayerRect.Left, (float)_activeLayerRect.Bottom);
134 |
135 | Graphics.Point topLeft = new Graphics.Point(corners[0].X, corners[0].Y);
136 | Graphics.Point bottomRight = new Graphics.Point(corners[0].X, corners[0].Y);
137 | for (int i = 1; i < 4; i++)
138 | {
139 | if (corners[i].X < topLeft.X)
140 | topLeft.X = corners[i].X;
141 | if (corners[i].X > bottomRight.X)
142 | bottomRight.X = corners[i].X;
143 |
144 | if (corners[i].Y < topLeft.Y)
145 | topLeft.Y = corners[i].Y;
146 | if (corners[i].Y > bottomRight.Y)
147 | bottomRight.Y = corners[i].Y;
148 | }
149 |
150 | _activeLayerRect.X = topLeft.X;
151 | _activeLayerRect.Y = topLeft.Y;
152 | _activeLayerRect.Width = bottomRight.X - topLeft.X;
153 | _activeLayerRect.Height = bottomRight.Y - topLeft.Y;
154 |
155 | _activeLayer.Dispose();
156 | _activeLayer = _session.CreateLayer(1.0f, _activeLayerRect);
157 | }
158 | }
159 | }
160 |
161 | public void SetStrokeColor(Color color)
162 | {
163 | _strokeColor = color.ToPlatform();
164 | }
165 |
166 | public void SetStrokeWidth(float width)
167 | {
168 | _strokeWidth = width;
169 | }
170 |
171 | public void SetStrokeLineCap(LineCap lineCap)
172 | {
173 | if (lineCap == LineCap.BUTT)
174 | {
175 | _strokeStyle.StartCap = CanvasCapStyle.Flat;
176 | _strokeStyle.EndCap = CanvasCapStyle.Flat;
177 | _strokeStyle.DashCap = CanvasCapStyle.Flat;
178 | }
179 | else if (lineCap == LineCap.ROUND)
180 | {
181 | _strokeStyle.StartCap = CanvasCapStyle.Round;
182 | _strokeStyle.EndCap = CanvasCapStyle.Round;
183 | _strokeStyle.DashCap = CanvasCapStyle.Round;
184 | }
185 | else if (lineCap == LineCap.SQUARE)
186 | {
187 | _strokeStyle.StartCap = CanvasCapStyle.Square;
188 | _strokeStyle.EndCap = CanvasCapStyle.Square;
189 | _strokeStyle.DashCap = CanvasCapStyle.Square;
190 | }
191 | }
192 |
193 | public void SetStrokeLineJoin(LineJoin lineJoin)
194 | {
195 | if (lineJoin == LineJoin.BEVEL)
196 | _strokeStyle.LineJoin = CanvasLineJoin.Bevel;
197 | else if (lineJoin == LineJoin.MITER)
198 | _strokeStyle.LineJoin = CanvasLineJoin.Miter;
199 | else if (lineJoin == LineJoin.ROUND)
200 | _strokeStyle.LineJoin = CanvasLineJoin.Round;
201 | }
202 |
203 | public void SetStrokeMiterLimit(float limit)
204 | {
205 | _strokeStyle.MiterLimit = limit;
206 | }
207 |
208 | public void SetStrokeDashArray(float[] array)
209 | {
210 | _strokeStyle.CustomDashStyle = array;
211 | }
212 |
213 | public void SetStrokeDashOffset(float offset)
214 | {
215 | _strokeStyle.DashOffset = offset;
216 | }
217 |
218 | public void SetFillColor(Color color)
219 | {
220 | _fillColor = color.ToPlatform();
221 | }
222 |
223 | public void SetFillRule(FillRule rule)
224 | {
225 | if (rule == FillRule.NONZERO)
226 | _fillRule = CanvasFilledRegionDetermination.Winding;
227 | else if (rule == FillRule.EVENODD)
228 | _fillRule = CanvasFilledRegionDetermination.Alternate;
229 | }
230 |
231 | public void SetDropShadow(float xOffset, float yOffset, float radius, Color color)
232 | {
233 | _dropShadowOffsetX = xOffset;
234 | _dropShadowOffsetY = yOffset;
235 | _dropShadowRadius = radius;
236 | _dropShadowColor = color.ToPlatform();
237 | }
238 |
239 | public void SetFontProperties(string family, float lineHeight, float size, string style, string variant, int weight)
240 | {
241 | _fontProperties.FontFamily = FontMetricsProvider.ToPlatformFontFamily(family, style, weight);
242 | _fontProperties.FontStyle = FontMetricsProvider.ToPlatformFontStyle(style);
243 | _fontProperties.FontWeight = FontMetricsProvider.ToPlatformFontWeight(weight);
244 | _fontProperties.FontSize = size;
245 |
246 | using (var canvasTextLayout = new CanvasTextLayout(_session.Device, "k", _fontProperties, float.MaxValue, float.MaxValue))
247 | {
248 | _baseline = canvasTextLayout.LineMetrics[0].Baseline;
249 | }
250 | }
251 |
252 | public void StartGroup(string id, float x, float y, float width, float height, bool clipContent)
253 | {
254 | if (clipContent)
255 | {
256 | _layers.Add(id, _activeLayerRect);
257 |
258 | if (_activeLayer != null)
259 | {
260 | _activeLayer.Dispose();
261 | _activeLayer = null;
262 | _activeLayerRect = Rect.Empty;
263 | }
264 |
265 | if (_session != null)
266 | {
267 | _activeLayerRect = new Rect(x, y, width, height);
268 | _activeLayer = _session.CreateLayer(1.0f, _activeLayerRect);
269 | }
270 | }
271 | }
272 |
273 | public void EndGroup(string id)
274 | {
275 | if (_layers.ContainsKey(id))
276 | {
277 | var rect = _layers[id];
278 |
279 | _layers.Remove(id);
280 |
281 | if (_activeLayer != null)
282 | {
283 | _activeLayer.Dispose();
284 | _activeLayer = null;
285 | _activeLayerRect = Rect.Empty;
286 | }
287 |
288 | if (rect.IsEmpty == false)
289 | {
290 | if (_session != null)
291 | {
292 | _activeLayerRect = rect;
293 | _activeLayer = _session.CreateLayer(1.0f, _activeLayerRect);
294 | }
295 | }
296 | }
297 | }
298 |
299 | public void StartItem(string id)
300 | {
301 | }
302 |
303 | public void EndItem(string id)
304 | {
305 | }
306 |
307 | public IPath CreatePath()
308 | {
309 | return new Path(_session.Device);
310 | }
311 |
312 | /// Draw Path to canvas according path
313 | public void DrawPath(IPath path)
314 | {
315 | var geometry = ((Path)path).CreateGeometry();
316 | var dropShadowTranslation = Matrix3x2.CreateTranslation(_dropShadowOffsetX, _dropShadowOffsetY).Translation;
317 |
318 | if (_fillColor.A > 0)
319 | {
320 | if (_dropShadowColor.A > 0)
321 | {
322 | _session.FillGeometry(geometry, dropShadowTranslation, _dropShadowColor);
323 | }
324 |
325 | _session.FillGeometry(geometry, _fillColor);
326 | }
327 |
328 | if (_strokeColor.A > 0)
329 | {
330 | if (_dropShadowColor.A > 0)
331 | {
332 | _session.DrawGeometry(geometry, dropShadowTranslation, _dropShadowColor, _strokeWidth, _strokeStyle);
333 | }
334 |
335 | _session.DrawGeometry(geometry, _strokeColor, _strokeWidth, _strokeStyle);
336 | }
337 | }
338 |
339 | /// Draw Rectangle to canvas according to region
340 | public void DrawRectangle(float x, float y, float width, float height)
341 | {
342 | if (_fillColor.A > 0)
343 | {
344 | if (_dropShadowColor.A > 0)
345 | {
346 | _session.FillRectangle(x + _dropShadowOffsetX, y + _dropShadowOffsetY, width, height, _dropShadowColor);
347 | }
348 |
349 | _session.FillRectangle(x, y, width, height, _fillColor);
350 | }
351 |
352 | if (_strokeColor.A > 0)
353 | {
354 | if (_dropShadowColor.A > 0)
355 | {
356 | _session.DrawRectangle(x + _dropShadowOffsetX, y + _dropShadowOffsetY, width, height, _dropShadowColor, _strokeWidth, _strokeStyle);
357 | }
358 |
359 | _session.DrawRectangle(x, y, width, height, _strokeColor, _strokeWidth, _strokeStyle);
360 | }
361 | }
362 |
363 | /// Draw Line to canvas according coordinates
364 | public void DrawLine(float x1, float y1, float x2, float y2)
365 | {
366 | if (_strokeColor.A > 0)
367 | {
368 | if (_dropShadowColor.A > 0)
369 | {
370 | _session.DrawLine(x1 + _dropShadowOffsetX, y1 + _dropShadowOffsetY, x2 + _dropShadowOffsetX, y2 + _dropShadowOffsetY, _dropShadowColor, _strokeWidth, _strokeStyle);
371 | }
372 |
373 | _session.DrawLine(x1, y1, x2, y2, _strokeColor, _strokeWidth, _strokeStyle);
374 | }
375 | }
376 |
377 | public void DrawObject(string url, string mimeType, float x, float y, float width, float height)
378 | {
379 | if (_imageLoader == null)
380 | return;
381 |
382 | var transform = _transform;
383 | var screenMin = transform.Apply(x, y);
384 | var screenMax = transform.Apply(x + width, y + height);
385 |
386 | var image = _imageLoader.getImage(url, mimeType);
387 |
388 | if (image == null)
389 | {
390 | // image is not ready yet...
391 | if (_fillColor.A > 0)
392 | {
393 | _session.FillRectangle(x, y, width, height, _fillColor);
394 | }
395 | }
396 | else
397 | {
398 | // adjust rectangle so that the image gets fit into original rectangle
399 | var size = image.SizeInPixels;
400 | float fx = width / (float)size.Width;
401 | float fy = height / (float)size.Height;
402 |
403 | if (fx > fy)
404 | {
405 | float w = (float)(size.Width) * fy;
406 | x += (width - w) / 2;
407 | width = w;
408 | }
409 | else
410 | {
411 | float h = (float)(size.Height) * fx;
412 | y += (height - h) / 2;
413 | height = h;
414 | }
415 |
416 | // draw the image
417 | var rect = new Rect(x, y, width, height);
418 | _session.DrawImage(image, rect, new Rect(0, 0, size.Width, size.Height));
419 | }
420 | }
421 |
422 | /// Draw Text to canvas according coordinates and label
423 | public void DrawText(string label, float x, float y, float xmin, float ymin, float xmax, float ymax)
424 | {
425 | if (_fillColor.A > 0)
426 | {
427 | if (_dropShadowColor.A > 0)
428 | {
429 | _session.DrawText(label, x + _dropShadowOffsetX, y + _dropShadowOffsetY - _baseline, _dropShadowColor, _fontProperties);
430 | }
431 |
432 | _session.DrawText(label, x, y - _baseline, _fillColor, _fontProperties);
433 | }
434 | }
435 |
436 |
437 | public void StartDraw(int x, int y, int width, int height)
438 | {
439 | Begin();
440 |
441 | if (ClearOnStartDraw)
442 | {
443 | EditorUserControl editor = _target as EditorUserControl;
444 | if (editor?.SupportsOffscreenRendering() ?? false)
445 | {
446 | var drawingLayerRect = new Rect(x, y, width, height);
447 | using (var drawingLayer = _session.CreateLayer(1.0f, drawingLayerRect))
448 | {
449 | var color = Windows.UI.Color.FromArgb((byte)0, (byte)0, (byte)0, (byte)0);
450 | _session.Clear(color);
451 | }
452 | }
453 | }
454 | }
455 |
456 | public void EndDraw()
457 | {
458 | End();
459 | }
460 |
461 | public void BlendOffscreen(UInt32 id,
462 | float src_x, float src_y, float src_width, float src_height,
463 | float dest_x, float dest_y, float dest_width, float dest_height,
464 | Color color)
465 | {
466 | EditorUserControl editor = _target as EditorUserControl;
467 | if (editor?.SupportsOffscreenRendering() ?? false)
468 | {
469 | CanvasRenderTarget bitmap = editor.GetImage(id);
470 |
471 | Rect srcRect = new Rect( src_x, src_y, src_width, src_height);
472 | Rect dstRect = new Rect(dest_x, dest_y, dest_width, dest_height);
473 |
474 | _session.DrawImage(bitmap, dstRect, srcRect, color.A_f);
475 | }
476 | }
477 | }
478 | }
479 |
--------------------------------------------------------------------------------
/UIReferenceImplementation/Constants/StyleKeys.cs:
--------------------------------------------------------------------------------
1 | // Copyright @ MyScript. All rights reserved.
2 |
3 | namespace MyScript.IInk.UIReferenceImplementation.Constants
4 | {
5 | public static class StyleKeys
6 | {
7 | public const string Color = "color";
8 | public const string MyScriptPenWidth = "-myscript-pen-width";
9 | }
10 | }
--------------------------------------------------------------------------------
/UIReferenceImplementation/Converters/BoolNegationConverter.cs:
--------------------------------------------------------------------------------
1 | // Copyright @ MyScript. All rights reserved.
2 |
3 | using System;
4 | using Windows.UI.Xaml.Data;
5 |
6 | namespace MyScript.IInk.UIReferenceImplementation.Converters
7 | {
8 | public class BoolNegationConverter : IValueConverter
9 | {
10 | public object Convert(object value, Type targetType, object parameter, string language)
11 | {
12 | return value is bool b && !b;
13 | }
14 |
15 | public object ConvertBack(object value, Type targetType, object parameter, string language)
16 | {
17 | throw new NotImplementedException();
18 | }
19 | }
20 | }
--------------------------------------------------------------------------------
/UIReferenceImplementation/EditorListener.cs:
--------------------------------------------------------------------------------
1 | // Copyright @ MyScript. All rights reserved.
2 |
3 | using Windows.UI.Core;
4 | using Windows.UI.Popups;
5 | using MyScript.IInk.UIReferenceImplementation.UserControls;
6 |
7 | namespace MyScript.IInk.UIReferenceImplementation
8 | {
9 | public class EditorListener : IEditorListener
10 | {
11 | private EditorUserControl _ucEditor;
12 |
13 | public EditorListener(EditorUserControl ucEditor)
14 | {
15 | _ucEditor = ucEditor;
16 | }
17 |
18 | public void PartChanged(Editor editor)
19 | {
20 | if (_ucEditor.SmartGuideEnabled && _ucEditor.SmartGuide != null)
21 | {
22 | var dispatcher = _ucEditor.Dispatcher;
23 | var task = dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { _ucEditor.SmartGuide.OnPartChanged(); });
24 | }
25 | }
26 |
27 | public void ContentChanged(Editor editor, string[] blockIds)
28 | {
29 | if (_ucEditor.SmartGuideEnabled && _ucEditor.SmartGuide != null)
30 | {
31 | var dispatcher = _ucEditor.Dispatcher;
32 | var task = dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { _ucEditor.SmartGuide.OnContentChanged(blockIds); });
33 | }
34 | }
35 |
36 | public void SelectionChanged(Editor editor)
37 | {
38 | if (_ucEditor.SmartGuideEnabled && _ucEditor.SmartGuide != null)
39 | {
40 | using (var selection = editor.GetSelection())
41 | {
42 | var mode = editor.GetSelectionMode();
43 | var blockIds = editor.GetIntersectingBlocks(selection);
44 | var dispatcher = _ucEditor.Dispatcher;
45 | var task = dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { _ucEditor.SmartGuide.OnSelectionChanged(blockIds, mode); });
46 | }
47 | }
48 | }
49 |
50 | public void ActiveBlockChanged(Editor editor, string blockId)
51 | {
52 | if (_ucEditor.SmartGuideEnabled && _ucEditor.SmartGuide != null)
53 | {
54 | var dispatcher = _ucEditor.Dispatcher;
55 | var task = dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { _ucEditor.SmartGuide.OnActiveBlockChanged(blockId); });
56 | }
57 | }
58 |
59 | public void OnError(Editor editor, string blockId, EditorError error, string message)
60 | {
61 | var dispatcher = _ucEditor.Dispatcher;
62 | var task = dispatcher.RunAsync(CoreDispatcherPriority.Normal,
63 | () =>
64 | {
65 | var dlg = new MessageDialog(message);
66 | var dlgTask = dlg.ShowAsync();
67 | });
68 | }
69 | }
70 | }
--------------------------------------------------------------------------------
/UIReferenceImplementation/Extensions/Primitives.cs:
--------------------------------------------------------------------------------
1 | // Copyright @ MyScript. All rights reserved.
2 |
3 | namespace MyScript.IInk.UIReferenceImplementation.Extensions
4 | {
5 | public static class Primitives
6 | {
7 | private const float MillimetersPerInch = 25.4f;
8 |
9 | public static float FromPixelToMillimeter(this double source, float dpi)
10 | {
11 | return ((float)source).FromPixelToMillimeter(dpi);
12 | }
13 |
14 | public static float FromMillimeterToPixel(this float source, float dpi)
15 | {
16 | // DPI: dots or pixels per inch
17 | // => dpi = pixels / inch
18 | // => pixels = dpi * inch
19 | var inch = source / MillimetersPerInch;
20 | return dpi * inch;
21 | }
22 |
23 | public static float FromPixelToMillimeter(this float source, float dpi)
24 | {
25 | // DPI: dots or pixels per inch
26 | // => dpi = pixels / inch
27 | // => inch = pixels / dpi
28 | var inch = source / dpi;
29 | return inch * MillimetersPerInch;
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/UIReferenceImplementation/Extensions/SDK.cs:
--------------------------------------------------------------------------------
1 | // Copyright @ MyScript. All rights reserved.
2 |
3 | using System;
4 | using System.Diagnostics;
5 | using Windows.Devices.Input;
6 | using Windows.UI.Input.Inking;
7 | using MyScript.IInk.Graphics;
8 | using MyScript.IInk.UIReferenceImplementation.Constants;
9 |
10 | namespace MyScript.IInk.UIReferenceImplementation.Extensions
11 | {
12 | public static class SDK
13 | {
14 | #region Editor
15 |
16 | public static void Apply(this Editor source, InkDrawingAttributes attributes)
17 | {
18 | if (!(source.ToolController is ToolController controller)) return;
19 | var dpi = source.Renderer?.DpiX ?? 96;
20 | var color = attributes.Color.ToNative().ToHex();
21 | var strokeWidth = attributes.DrawAsHighlighter ? attributes.Size.Height : attributes.Size.Width;
22 | var css =
23 | $"{StyleKeys.Color}: {color}; " +
24 | $"{StyleKeys.MyScriptPenWidth}: {strokeWidth.FromPixelToMillimeter(dpi)}";
25 | var pointerTool = attributes.DrawAsHighlighter ? PointerTool.HIGHLIGHTER : PointerTool.PEN;
26 | controller.SetToolStyle(pointerTool, css);
27 | }
28 |
29 | #endregion
30 |
31 | #region Pointer Type
32 |
33 | public static PointerType ToNative(this PointerDeviceType source)
34 | {
35 | switch (source)
36 | {
37 | case PointerDeviceType.Touch:
38 | return PointerType.TOUCH;
39 | case PointerDeviceType.Pen:
40 | return PointerType.PEN;
41 | case PointerDeviceType.Mouse:
42 | return PointerType.MOUSE;
43 | default:
44 | throw new ArgumentOutOfRangeException(nameof(source), source, null);
45 | }
46 | }
47 |
48 | #endregion
49 |
50 | #region Colors
51 |
52 | public static string ToHex(this Color source)
53 | {
54 | return $"#{source.R:X2}{source.G:X2}{source.B:X2}{source.A:X2}";
55 | }
56 |
57 | public static Color ToNative(this Windows.UI.Color source)
58 | {
59 | return new Color(source.R, source.G, source.B, source.A);
60 | }
61 |
62 | public static Windows.UI.Color ToPlatform(this Color source)
63 | {
64 | return new Windows.UI.Color
65 | { A = (byte)source.A, B = (byte)source.B, G = (byte)source.G, R = (byte)source.R };
66 | }
67 |
68 | #endregion
69 | }
70 | }
--------------------------------------------------------------------------------
/UIReferenceImplementation/FontMetricsProvider.cs:
--------------------------------------------------------------------------------
1 | // Copyright @ MyScript. All rights reserved.
2 |
3 | using Microsoft.Graphics.Canvas;
4 | using Microsoft.Graphics.Canvas.Text;
5 | using MyScript.IInk.Graphics;
6 | using MyScript.IInk.Text;
7 | using System.Collections.Generic;
8 | using System.Globalization;
9 | using System.Linq;
10 |
11 | namespace MyScript.IInk.UIReferenceImplementation
12 | {
13 | internal static class FontFamilies
14 | {
15 | public static string MyScriptInter { get { return _myScriptInter ?? _defaultFamily; } private set { _myScriptInter = value; } }
16 | public static string MyScriptInterBold { get { return _myScriptInterBold ?? _defaultFamily; } private set { _myScriptInterBold = value; } }
17 | public static string StixRegular { get { return _stixRegular ?? _defaultStixFamily; } private set { _stixRegular = value; } }
18 | public static string StixItalic { get { return _stixItalic ?? _defaultStixFamily; } private set { _stixItalic = value; } }
19 |
20 | private const string _defaultFamily = "Segoe UI";
21 | private const string _defaultStixFamily = "STIX";
22 |
23 | private const string _fontFolder = "fonts";
24 |
25 | private static bool _initialized = false;
26 | private static string _myScriptInter;
27 | private static string _myScriptInterBold;
28 | private static string _stixRegular;
29 | private static string _stixItalic;
30 |
31 | private static string RegisterFontFamily(string filename, string name, string defaultFamily)
32 | {
33 | var localPath = System.IO.Path.Combine(_fontFolder, filename);
34 | var fullPath = System.IO.Path.Combine(Windows.ApplicationModel.Package.Current.InstalledLocation.Path, localPath);
35 |
36 | if (System.IO.File.Exists(fullPath))
37 | return "ms-appx:///" + localPath + "#" + name;
38 |
39 | return defaultFamily;
40 | }
41 |
42 | public static void Initialize()
43 | {
44 | if (_initialized)
45 | return;
46 |
47 | MyScriptInter = RegisterFontFamily("MyScriptInter-Regular.otf", "MyScriptInter", _defaultFamily);
48 | MyScriptInterBold = RegisterFontFamily("MyScriptInter-Bold.otf", "MyScriptInter", _defaultFamily);
49 | StixRegular = RegisterFontFamily("STIXTwoMath-Regular.otf", "STIX Two Math", _defaultStixFamily);
50 | StixItalic = RegisterFontFamily("STIXTwoText-Italic.otf", "STIX Two Text", _defaultStixFamily);
51 |
52 | _initialized = true;
53 | }
54 | }
55 |
56 | public class FontMetricsProvider : IFontMetricsProvider
57 | {
58 | public const bool UseColorFont = true;
59 |
60 | private float _dpiX;
61 | private float _dpiY;
62 |
63 | public static void Initialize()
64 | {
65 | FontFamilies.Initialize();
66 | }
67 |
68 | public FontMetricsProvider(float dpiX, float dpiY)
69 | {
70 | _dpiX = dpiX;
71 | _dpiY = dpiY;
72 | }
73 |
74 | public static string ToPlatformFontFamily(string family, string style, int weight)
75 | {
76 | if (family == "MyScriptInter")
77 | return ToPlatformFontWeight(weight).Equals(Windows.UI.Text.FontWeights.Bold) ? FontFamilies.MyScriptInterBold : FontFamilies.MyScriptInter;
78 | else if (family == "STIX")
79 | return (ToPlatformFontStyle(style) == Windows.UI.Text.FontStyle.Italic) ? FontFamilies.StixItalic : FontFamilies.StixRegular;
80 |
81 | return family;
82 | }
83 |
84 | public static Windows.UI.Text.FontWeight ToPlatformFontWeight(int weight)
85 | {
86 | var fontWeight = Windows.UI.Text.FontWeights.Normal;
87 |
88 | if (weight >= 700)
89 | fontWeight = Windows.UI.Text.FontWeights.Bold;
90 | else if (weight >= 400)
91 | fontWeight = Windows.UI.Text.FontWeights.Normal;
92 | else
93 | fontWeight = Windows.UI.Text.FontWeights.Light;
94 |
95 | return fontWeight;
96 | }
97 |
98 | public static Windows.UI.Text.FontStyle ToPlatformFontStyle(string style)
99 | {
100 | var fontStyle = Windows.UI.Text.FontStyle.Normal;
101 |
102 | if (style.Equals("italic"))
103 | fontStyle = Windows.UI.Text.FontStyle.Italic;
104 | else if (style.Equals("oblique"))
105 | fontStyle = Windows.UI.Text.FontStyle.Oblique;
106 |
107 | return fontStyle;
108 | }
109 |
110 | private static float px2mm(float px, float dpi)
111 | {
112 | return 25.4f * (px / dpi);
113 | }
114 |
115 | private static float mm2px(float mmm, float dpi)
116 | {
117 | return (mmm / 25.4f) * dpi;
118 | }
119 |
120 | private class FontKey
121 | {
122 | public string FontFamily { get; }
123 | public float FontSize { get; }
124 | public Windows.UI.Text.FontWeight FontWeight { get; }
125 | public Windows.UI.Text.FontStyle FontStyle { get; }
126 |
127 | public FontKey(string fontFamily, float fontSize, Windows.UI.Text.FontWeight fontWeight, Windows.UI.Text.FontStyle fontStyle)
128 | {
129 | this.FontFamily = fontFamily;
130 | this.FontSize = fontSize;
131 | this.FontWeight = fontWeight;
132 | this.FontStyle = fontStyle;
133 | }
134 |
135 | public override bool Equals(object obj)
136 | {
137 | if (obj.GetType() != this.GetType())
138 | return false;
139 |
140 | FontKey other = (FontKey)obj;
141 | return this.FontFamily == other.FontFamily && this.FontSize == other.FontSize && this.FontWeight.Weight == other.FontWeight.Weight && this.FontStyle == other.FontStyle;
142 | }
143 |
144 | public override int GetHashCode()
145 | {
146 | return FontFamily.GetHashCode() ^ FontSize.GetHashCode() ^ FontWeight.Weight.GetHashCode() ^ FontStyle.GetHashCode();
147 | }
148 | }
149 | private Dictionary> cache = new Dictionary>();
150 |
151 | private FontKey FontKeyFromStyle(Style style)
152 | {
153 | var fontFamily = ToPlatformFontFamily(style.FontFamily, style.FontStyle, style.FontWeight);
154 | var fontSize = mm2px(style.FontSize, _dpiY);
155 | var fontWeight = ToPlatformFontWeight(style.FontWeight);
156 | var fontStyle = ToPlatformFontStyle(style.FontStyle);
157 | return new FontKey(fontFamily, fontSize, fontWeight, fontStyle);
158 | }
159 |
160 | private GlyphMetrics GetGlyphMetrics(FontKey fontKey, string glyphLabel, CanvasDevice canvasDevice)
161 | {
162 | Dictionary fontCache = null;
163 | if (!cache.TryGetValue(fontKey, out fontCache))
164 | {
165 | fontCache = new Dictionary();
166 | cache[fontKey] = fontCache;
167 | }
168 |
169 | GlyphMetrics value = null;
170 | if (!fontCache.TryGetValue(glyphLabel, out value))
171 | {
172 | var textFormat = new CanvasTextFormat()
173 | {
174 | FontSize = fontKey.FontSize,
175 | FontFamily = fontKey.FontFamily,
176 | FontStyle = fontKey.FontStyle,
177 | FontWeight = fontKey.FontWeight,
178 | WordWrapping = CanvasWordWrapping.NoWrap,
179 | Options = UseColorFont ? CanvasDrawTextOptions.EnableColorFont : CanvasDrawTextOptions.Default
180 | };
181 |
182 | using (var canvasCharLayout = new CanvasTextLayout(canvasDevice, glyphLabel, textFormat, 0.0f, 0.0f))
183 | {
184 | int charCount = 0;
185 | if (canvasCharLayout.ClusterMetrics != null)
186 | {
187 | foreach (var c in canvasCharLayout.ClusterMetrics)
188 | charCount += c.CharacterCount;
189 | }
190 |
191 | var rect = canvasCharLayout.DrawBounds;
192 | var left = (float)rect.Left;
193 | var top = (float)rect.Top - canvasCharLayout.LineMetrics[0].Baseline;
194 | var leftBearing = (float)(-rect.Left);
195 | var height = (float)rect.Height;
196 |
197 | var charEnd = (charCount > 0) ? (charCount - 1) : 0;
198 | var advance = canvasCharLayout.GetCaretPosition(charEnd, true);
199 | var width = (float)rect.Width;
200 | var right = (float)rect.Right;
201 | var rightBearing = (float)advance.X - right;
202 |
203 | var glyphX = px2mm(left, _dpiX);
204 | var glyphY = px2mm(top, _dpiY);
205 | var glyphW = px2mm(width, _dpiX);
206 | var glyphH = px2mm(height, _dpiY);
207 | var glyphRect = new Rectangle(glyphX, glyphY, glyphW, glyphH);
208 | var glyphLeftBearing = px2mm(leftBearing, _dpiX);
209 | var glyphRightBearing = px2mm(rightBearing, _dpiX);
210 |
211 | value = new GlyphMetrics(glyphRect, glyphLeftBearing, glyphRightBearing);
212 | fontCache[glyphLabel] = value;
213 | }
214 | }
215 |
216 | return new GlyphMetrics(new Rectangle(value.BoundingBox.X, value.BoundingBox.Y, value.BoundingBox.Width, value.BoundingBox.Height), value.LeftSideBearing, value.RightSideBearing);
217 | }
218 |
219 | public Rectangle[] GetCharacterBoundingBoxes(MyScript.IInk.Text.Text text, TextSpan[] spans)
220 | {
221 | var glyphMetrics = GetGlyphMetrics(text, spans);
222 |
223 | Rectangle[] rectangles = new Rectangle[glyphMetrics.Length];
224 | for (int i = 0; i < glyphMetrics.Length; ++i)
225 | rectangles[i] = glyphMetrics[i].BoundingBox;
226 |
227 | return rectangles;
228 | }
229 |
230 | public float GetFontSizePx(Style style)
231 | {
232 | return style.FontSize;
233 | }
234 |
235 | public bool SupportsGlyphMetrics()
236 | {
237 | return true;
238 | }
239 |
240 | public GlyphMetrics[] GetGlyphMetrics(MyScript.IInk.Text.Text text, TextSpan[] spans)
241 | {
242 | CanvasDevice canvasDevice = CanvasDevice.GetSharedDevice();
243 |
244 | GlyphMetrics[] glyphMetrics = new GlyphMetrics[text.GlyphCount];
245 |
246 | var firstStyle = spans[0].Style;
247 | var firstFontKey = FontKeyFromStyle(firstStyle);
248 |
249 | if (text.GlyphCount == 1)
250 | {
251 | glyphMetrics[0] = GetGlyphMetrics(firstFontKey, text.Label, canvasDevice);
252 | }
253 | else
254 | {
255 | var textFormat = new CanvasTextFormat()
256 | {
257 | FontSize = firstFontKey.FontSize,
258 | FontFamily = firstFontKey.FontFamily,
259 | FontStyle = firstFontKey.FontStyle,
260 | FontWeight = firstFontKey.FontWeight,
261 | WordWrapping = CanvasWordWrapping.NoWrap,
262 | Options = UseColorFont ? CanvasDrawTextOptions.EnableColorFont : CanvasDrawTextOptions.Default
263 | };
264 |
265 | using (var canvasTextLayout = new CanvasTextLayout(canvasDevice, text.Label, textFormat, 0.0f, 0.0f))
266 | {
267 | for (int i = 0; i < spans.Length; ++i)
268 | {
269 | var charIndex = text.GetGlyphBeginAt(spans[i].BeginPosition);
270 | var charCount = text.GetGlyphEndAt(spans[i].EndPosition - 1) - charIndex;
271 |
272 | var style = spans[i].Style;
273 | var fontKey = FontKeyFromStyle(style);
274 |
275 | canvasTextLayout.SetFontFamily(charIndex, charCount, fontKey.FontFamily);
276 | canvasTextLayout.SetFontSize(charIndex, charCount, fontKey.FontSize);
277 | canvasTextLayout.SetFontWeight(charIndex, charCount, fontKey.FontWeight);
278 | canvasTextLayout.SetFontStyle(charIndex, charCount, fontKey.FontStyle);
279 | }
280 |
281 | for (int i = 0; i < text.GlyphCount; ++i)
282 | {
283 | var glyphLabel = text.GetGlyphLabelAt(i);
284 | var glyphCharStart = text.GetGlyphBeginAt(i);
285 | var glyphCharEnd = text.GetGlyphEndAt(i);
286 |
287 | var glyphFontKey = new FontKey ( canvasTextLayout.GetFontFamily(glyphCharStart)
288 | , canvasTextLayout.GetFontSize(glyphCharStart)
289 | , canvasTextLayout.GetFontWeight(glyphCharStart)
290 | , canvasTextLayout.GetFontStyle(glyphCharStart));
291 |
292 | var glyphMetrics_ = GetGlyphMetrics(glyphFontKey, glyphLabel, canvasDevice);
293 |
294 | // Find cluster associated with element
295 | // (Use of ClusterMetrics to identify ligatures in the CanvasTextLayout)
296 | int cluster = -1;
297 | int clusterCharStart = 0;
298 |
299 | if (canvasTextLayout.ClusterMetrics != null)
300 | {
301 | for (int c = 0; c < canvasTextLayout.ClusterMetrics.Length; ++c)
302 | {
303 | var clusterCharCount = canvasTextLayout.ClusterMetrics[c].CharacterCount;
304 | if ((glyphCharStart >= clusterCharStart) && (glyphCharStart < (clusterCharStart + clusterCharCount)))
305 | {
306 | cluster = c;
307 | break;
308 | }
309 |
310 | clusterCharStart += clusterCharCount;
311 | }
312 | }
313 |
314 | if ( (i > 0) && (cluster >= 0) && (glyphCharStart > clusterCharStart) )
315 | {
316 | // Ligature with the previous glyph
317 | // The position is not accurate because of glyphs substitution at rendering
318 | // but it makes the illusion.
319 | var prevGlyphMetrics = glyphMetrics[i-1];
320 | glyphMetrics_.BoundingBox.X = prevGlyphMetrics.BoundingBox.X
321 | + prevGlyphMetrics.BoundingBox.Width
322 | + prevGlyphMetrics.RightSideBearing
323 | + glyphMetrics_.LeftSideBearing;
324 | }
325 | else
326 | {
327 | float glyphX = 0.0f;
328 | var charRegions = canvasTextLayout.GetCharacterRegions(glyphCharStart, glyphCharEnd - glyphCharStart);
329 |
330 | if ((charRegions != null) && (charRegions.Length > 0))
331 | {
332 | glyphX = (float)charRegions[0].LayoutBounds.X;
333 | }
334 | else
335 | {
336 | var glyphPos = canvasTextLayout.GetCaretPosition(glyphCharStart, false);
337 | glyphX = (float)glyphPos.X;
338 | }
339 |
340 | glyphMetrics_.BoundingBox.X += px2mm(glyphX, _dpiX);
341 | }
342 |
343 | glyphMetrics[i] = glyphMetrics_;
344 | }
345 | }
346 | }
347 |
348 | return glyphMetrics;
349 | }
350 | };
351 | }
352 |
--------------------------------------------------------------------------------
/UIReferenceImplementation/ImageLoader.cs:
--------------------------------------------------------------------------------
1 | // Copyright @ MyScript. All rights reserved.
2 |
3 | using Microsoft.Graphics.Canvas;
4 | using System;
5 | using Windows.UI;
6 | using System.Collections.Generic;
7 |
8 | namespace MyScript.IInk.UIReferenceImplementation
9 | {
10 | // LruImgCache
11 | public class LruImgCache
12 | {
13 | private LinkedList _lru = new LinkedList();
14 | private Dictionary _cache = new Dictionary();
15 | private int _maxBytes;
16 | private int _curBytes;
17 |
18 | // ImageNode
19 | public struct ImageNode
20 | {
21 | public ImageNode(CanvasBitmap image, int cost)
22 | {
23 | Image = image;
24 | Cost = cost;
25 | }
26 |
27 | public CanvasBitmap Image { get; }
28 | public int Cost { get; }
29 | }
30 |
31 | public LruImgCache(int maxBytes)
32 | {
33 | _maxBytes = maxBytes;
34 | _curBytes = 0;
35 | }
36 |
37 | public bool containsBitmap(string url)
38 | {
39 | return _cache.ContainsKey(url);
40 | }
41 |
42 | public CanvasBitmap getBitmap(string url)
43 | {
44 | // Update LRU
45 | _lru.Remove(url);
46 | _lru.AddFirst(url);
47 |
48 | return _cache[url].Image;
49 | }
50 |
51 | public void putBitmap(string url, Editor editor)
52 | {
53 | CanvasBitmap image = loadBitmap(url, editor);
54 | var imageBytes = image.GetPixelBytes().Length;
55 |
56 | // Too big for cache
57 | if (imageBytes > _maxBytes)
58 | {
59 | // Use fallback (cache it to avoid reloading it each time for size check)
60 | image = createFallbackBitmap();
61 | imageBytes = 4;
62 | }
63 |
64 | // Remove LRUs if max size reached
65 | while (_curBytes + imageBytes > _maxBytes)
66 | {
67 | string lruKey = _lru.Last.Value;
68 | ImageNode lruNode = _cache[lruKey];
69 | _curBytes -= lruNode.Cost;
70 | _cache.Remove(lruKey);
71 | _lru.RemoveLast();
72 | }
73 |
74 | // Add to cache
75 | _cache.Add(url, new ImageNode(image, imageBytes));
76 | _curBytes += imageBytes;
77 | _lru.AddFirst(url);
78 | }
79 |
80 | private CanvasBitmap loadBitmap(string url, Editor editor)
81 | {
82 | var dpi = Math.Max(editor.Renderer.DpiX, editor.Renderer.DpiY);
83 | var path = System.IO.Path.GetFullPath(url);
84 |
85 | try
86 | {
87 | CanvasBitmap image = null;
88 | var task = System.Threading.Tasks.Task.Run(async ()
89 | => { image = await CanvasBitmap.LoadAsync(CanvasDevice.GetSharedDevice(), path, dpi); });
90 | if (task != null)
91 | System.Threading.Tasks.Task.WaitAll(task);
92 |
93 | if (image != null)
94 | return image;
95 | }
96 | catch
97 | {
98 | // Error: use fallback bitmap
99 | }
100 |
101 | // Fallback
102 | return createFallbackBitmap();
103 | }
104 |
105 | public static CanvasBitmap createFallbackBitmap()
106 | {
107 | // Fallback 1x1 bitmap
108 | var dpi = 96;
109 | var image = new CanvasRenderTarget(CanvasDevice.GetSharedDevice(), 1, 1, dpi);
110 | Color[] color = new Color[] { Color.FromArgb(255, 255, 255, 255) };
111 | image.SetPixelColors(color, 0, 0, 1, 1);
112 |
113 | return image;
114 | }
115 | }
116 |
117 | // ImageLoader
118 | public class ImageLoader
119 | {
120 | private Editor _editor;
121 | private LruImgCache _cache;
122 | private const int CACHE_MAX_BYTES = 200 * 1000000; // 200M (in Bytes)
123 |
124 | public Editor Editor
125 | {
126 | get
127 | {
128 | return _editor;
129 | }
130 | }
131 |
132 | public ImageLoader(Editor editor, string cacheDirectory)
133 | {
134 | _editor = editor;
135 | _cache = new LruImgCache(CACHE_MAX_BYTES);
136 | }
137 |
138 | public CanvasBitmap getImage(string url, string mimeType)
139 | {
140 | CanvasBitmap image = null;
141 |
142 | lock (_cache)
143 | {
144 | if (!_cache.containsBitmap(url))
145 | _cache.putBitmap(url, _editor);
146 | image = _cache.getBitmap(url);
147 | }
148 |
149 | if (image == null)
150 | image = LruImgCache.createFallbackBitmap();
151 |
152 | return image;
153 | }
154 | }
155 | }
156 |
--------------------------------------------------------------------------------
/UIReferenceImplementation/ImagePainter.cs:
--------------------------------------------------------------------------------
1 | // Copyright @ MyScript. All rights reserved.
2 |
3 | using Microsoft.Graphics.Canvas;
4 | using MyScript.IInk.Graphics;
5 | using System;
6 |
7 | namespace MyScript.IInk.UIReferenceImplementation
8 | {
9 | public class ImagePainter : IImagePainter
10 | {
11 | private static Color _defaultBackgroundColor = new Color(0xffffffff);
12 |
13 | private CanvasRenderTarget _image;
14 | private CanvasDrawingSession _session;
15 | private Canvas _canvas;
16 |
17 | public ImageLoader ImageLoader { get; set; }
18 | public Graphics.Color BackgroundColor { get; set; }
19 |
20 | public ImagePainter()
21 | {
22 | BackgroundColor = _defaultBackgroundColor;
23 | }
24 |
25 | public void PrepareImage(int width, int height, float dpi)
26 | {
27 | if (_image != null)
28 | _image = null;
29 |
30 | // Use 96 dpi to match the default DIP unit used by UWP
31 | _image = new CanvasRenderTarget(CanvasDevice.GetSharedDevice(), width, height, 96);
32 | _session = _image.CreateDrawingSession();
33 |
34 | var color = (BackgroundColor != null) ? BackgroundColor : _defaultBackgroundColor;
35 | _canvas = new Canvas(_session, null, ImageLoader);
36 | _canvas.Begin();
37 | _canvas.Clear(color);
38 | }
39 |
40 | public void SaveImage(string path)
41 | {
42 | if ((_image != null) && !string.IsNullOrWhiteSpace(path))
43 | {
44 | _canvas.End();
45 | _session.Dispose();
46 | _session = null;
47 | var task = System.Threading.Tasks.Task.Run(async() => { await _image.SaveAsync(path); });
48 | if (task != null)
49 | System.Threading.Tasks.Task.WaitAll(task);
50 | }
51 | _image = null;
52 | }
53 |
54 | public ICanvas CreateCanvas()
55 | {
56 | return _canvas;
57 | }
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/UIReferenceImplementation/Layer.cs:
--------------------------------------------------------------------------------
1 | // Copyright @ MyScript. All rights reserved.
2 |
3 | using Microsoft.Graphics.Canvas.UI.Xaml;
4 | using Windows.Foundation;
5 | using Windows.UI.Core;
6 |
7 | namespace MyScript.IInk.UIReferenceImplementation
8 | {
9 | public class Layer
10 | {
11 | public ImageLoader ImageLoader { get; set; }
12 |
13 | private CanvasVirtualControl _control;
14 | private IRenderTarget _target;
15 | private Renderer _renderer ;
16 |
17 | public Layer(CanvasVirtualControl control, IRenderTarget target, Renderer renderer)
18 | {
19 | _control = control;
20 | _target = target;
21 | _renderer = renderer;
22 | }
23 |
24 | public void Update()
25 | {
26 | // It must be done on UI thread
27 | var task = _control.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
28 | () =>
29 | {
30 | _control.Invalidate();
31 | });
32 | }
33 |
34 | private void Update_(int x, int y, int width, int height)
35 | {
36 | // Clamp region's coordinates into control's rect
37 | // (control.Invalidate may raise an exception)
38 | var region = ClampRect(x, y, width, height);
39 |
40 | if (region.Width > 0 && region.Height > 0)
41 | {
42 | _control.Invalidate(region);
43 | }
44 | }
45 |
46 | public void Update(int x, int y, int width, int height)
47 | {
48 | // It must be done on UI thread
49 | var task = _control.Dispatcher.RunAsync(CoreDispatcherPriority.Normal,
50 | () =>
51 | {
52 | Update_(x, y, width, height);
53 | });
54 | }
55 |
56 | /// Retranscribe draw with renderer
57 | public void OnPaint(int x, int y, int width, int height)
58 | {
59 | // Clamp region's coordinates into control's rect
60 | // (control.CreateDrawingSession may raise an exception)
61 | var region = ClampRect(x, y, width, height);
62 | if (region.Width <= 0 || region.Height <= 0)
63 | return;
64 |
65 | using (var session = _control.CreateDrawingSession(region))
66 | {
67 | var canvas = new Canvas(session, _target, ImageLoader);
68 |
69 | canvas.ClearOnStartDraw = true;
70 | _renderer.DrawModel(x, y, width, height, canvas);
71 |
72 | canvas.ClearOnStartDraw = false;
73 | _renderer.DrawCaptureStrokes(x, y, width, height, canvas);
74 | }
75 | }
76 |
77 | /// Clamp rect's coordinates into control's rect
78 | private Rect ClampRect(int x, int y, int width, int height)
79 | {
80 | if (x < 0)
81 | {
82 | width += x;
83 | x = 0;
84 | }
85 | if (y < 0)
86 | {
87 | height += y;
88 | y = 0;
89 | }
90 | if ((x + width) > _control.ActualWidth)
91 | {
92 | width = (int)(_control.ActualWidth - x);
93 | }
94 | if ((y + height) > _control.ActualHeight)
95 | {
96 | height = (int)(_control.ActualHeight - y);
97 | }
98 |
99 | return new Rect(x, y, width > 0 ? width : 0, height > 0 ? height : 0);
100 | }
101 | };
102 | }
103 |
--------------------------------------------------------------------------------
/UIReferenceImplementation/MyScript.InteractiveInk.UIReferenceImplementation.Uwp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | obj
6 | bin
7 |
8 |
9 |
10 | Debug
11 | AnyCPU
12 | {667892F3-1761-4EA9-BDFA-71944C768BAD}
13 | Library
14 | Properties
15 | MyScript.IInk.UIReferenceImplementation
16 | MyScript.InteractiveInk.UIReferenceImplementation.Uwp
17 | en-US
18 | UAP
19 | 10.0.22621.0
20 | 10.0.17763.0
21 | 14
22 | 512
23 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
24 |
25 |
26 |
27 | 6.2.13
28 |
29 |
30 | 4.1.0
31 |
32 |
33 | 4.7.1
34 |
35 |
36 | 1.25.0
37 |
38 |
39 |
40 | x64
41 | true
42 | $(BaseOutputPath)\$(Platform)\$(Configuration)\
43 | $(BaseIntermediateOutputPath)\$(Platform)\$(Configuration)\
44 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
45 | ;2008
46 | full
47 | x64
48 | false
49 | prompt
50 |
51 |
52 | x64
53 | $(BaseOutputPath)\$(Platform)\$(Configuration)\
54 | $(BaseIntermediateOutputPath)\$(Platform)\$(Configuration)\
55 | TRACE;NETFX_CORE;WINDOWS_UWP
56 | true
57 | ;2008
58 | pdbonly
59 | x64
60 | false
61 | prompt
62 |
63 |
64 | PackageReference
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 | EditorUserControl.xaml
82 |
83 |
84 | InkToolbar.xaml
85 |
86 |
87 | SmartGuideUserControl.xaml
88 |
89 |
90 |
91 |
92 |
93 | MSBuild:Compile
94 | Designer
95 |
96 |
97 | MSBuild:Compile
98 | Designer
99 |
100 |
101 | MSBuild:Compile
102 | Designer
103 |
104 |
105 |
106 | 15.0
107 |
108 |
109 |
116 |
117 |
--------------------------------------------------------------------------------
/UIReferenceImplementation/Path.cs:
--------------------------------------------------------------------------------
1 | // Copyright @ MyScript. All rights reserved.
2 |
3 | using MyScript.IInk.Graphics;
4 | using Microsoft.Graphics.Canvas;
5 | using Microsoft.Graphics.Canvas.Geometry;
6 |
7 | namespace MyScript.IInk.UIReferenceImplementation
8 | {
9 | public class Path : IPath
10 | {
11 | private CanvasPathBuilder _pathBuilder;
12 | private CanvasGeometry _cachedPath; // still valid after _pathBuilder is disposed
13 | private bool _isInFigure;
14 | private bool _isConfigured;
15 |
16 | public Path(CanvasDevice device)
17 | {
18 | _pathBuilder = new CanvasPathBuilder(device);
19 | _cachedPath = null;
20 | _isInFigure = false;
21 | _isConfigured = false;
22 | }
23 |
24 | public uint UnsupportedOperations
25 | {
26 | get { return (uint)PathOperation.ARC_OPS; }
27 | }
28 |
29 | public void MoveTo(float x, float y)
30 | {
31 | if (!_isConfigured)
32 | {
33 | // Settings must be set from Canvas properties and before BeginFigure
34 | _pathBuilder.SetSegmentOptions(CanvasFigureSegmentOptions.None);
35 | _pathBuilder.SetFilledRegionDetermination(CanvasFilledRegionDetermination.Winding);
36 | _isConfigured = true;
37 | }
38 |
39 | if (_isInFigure)
40 | {
41 | _pathBuilder.EndFigure(CanvasFigureLoop.Open);
42 | }
43 |
44 | _pathBuilder.BeginFigure(x, y);
45 | _isInFigure = true;
46 | _cachedPath = null;
47 | }
48 |
49 | public void LineTo(float x, float y)
50 | {
51 | _pathBuilder.AddLine(x, y);
52 | _cachedPath = null;
53 | }
54 |
55 | public void CurveTo(float x1, float y1, float x2, float y2, float x, float y)
56 | {
57 | var controlPoint1 = new System.Numerics.Vector2(x1, y1);
58 | var controlPoint2 = new System.Numerics.Vector2(x2, y2);
59 | var endPoint = new System.Numerics.Vector2(x, y);
60 |
61 | _pathBuilder.AddCubicBezier(controlPoint1, controlPoint2, endPoint);
62 | _cachedPath = null;
63 | }
64 |
65 | public void QuadTo(float x1, float y1, float x, float y)
66 | {
67 | var controlPoint = new System.Numerics.Vector2(x1, y1);
68 | var endPoint = new System.Numerics.Vector2(x, y);
69 |
70 | _pathBuilder.AddQuadraticBezier(controlPoint, endPoint);
71 | _cachedPath = null;
72 | }
73 |
74 | public void ArcTo(float rx, float ry, float phi, bool fA, bool fS, float x, float y)
75 | {
76 | // not supported, see unsupportedOperations
77 | }
78 |
79 | public void ClosePath()
80 | {
81 | _pathBuilder.EndFigure(CanvasFigureLoop.Closed);
82 | _isInFigure = false;
83 | _cachedPath = null;
84 | }
85 |
86 | public CanvasGeometry CreateGeometry()
87 | {
88 | if (_isInFigure)
89 | {
90 | _pathBuilder.EndFigure(CanvasFigureLoop.Open);
91 | _isInFigure = false;
92 | }
93 | else if (_cachedPath != null)
94 | {
95 | return _cachedPath;
96 | }
97 | _cachedPath = CanvasGeometry.CreatePath(_pathBuilder);
98 | return _cachedPath;
99 | }
100 | };
101 | }
102 |
--------------------------------------------------------------------------------
/UIReferenceImplementation/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("MyScript.InteractiveInk.UIReferenceImplementation.Uwp")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("MyScript")]
12 | [assembly: AssemblyProduct("MyScript.InteractiveInk.UIReferenceImplementation.Uwp")]
13 | [assembly: AssemblyCopyright("Copyright @ MyScript. All rights reserved.")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Version information for an assembly consists of the following four values:
18 | //
19 | // Major Version
20 | // Minor Version
21 | // Build Number
22 | // Revision
23 | //
24 | // You can specify all the values or you can default the Build and Revision Numbers
25 | // by using the '*' as shown below:
26 | // [assembly: AssemblyVersion("1.0.*")]
27 | [assembly: AssemblyVersion("4.1.0.0")]
28 | [assembly: AssemblyFileVersion("4.1.0.0")]
29 | [assembly: ComVisible(false)]
30 |
--------------------------------------------------------------------------------
/UIReferenceImplementation/Properties/MyScript.InteractiveInk.UIReferenceImplementation.rd.xml:
--------------------------------------------------------------------------------
1 |
2 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/UIReferenceImplementation/Properties/iink_sdk_examples_uwp.UIRefImpl.rd.xml:
--------------------------------------------------------------------------------
1 |
2 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/UIReferenceImplementation/RendererListener.cs:
--------------------------------------------------------------------------------
1 | // Copyright @ MyScript. All rights reserved.
2 |
3 | using Windows.UI.Core;
4 | using MyScript.IInk.UIReferenceImplementation.UserControls;
5 |
6 | namespace MyScript.IInk.UIReferenceImplementation
7 | {
8 | public class RendererListener : IRendererListener
9 | {
10 | private EditorUserControl _ucEditor;
11 |
12 | public RendererListener(EditorUserControl ucEditor)
13 | {
14 | _ucEditor = ucEditor;
15 | }
16 |
17 | public void ViewTransformChanged(Renderer renderer)
18 | {
19 | if (_ucEditor.SmartGuideEnabled && _ucEditor.SmartGuide != null)
20 | {
21 | var dispatcher = _ucEditor.Dispatcher;
22 | var task = dispatcher.RunAsync(CoreDispatcherPriority.Normal, () => { _ucEditor.SmartGuide.OnTransformChanged(); });
23 | }
24 | }
25 | }
26 | }
--------------------------------------------------------------------------------
/UIReferenceImplementation/UserControls/EditorUserControl.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
21 |
22 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/UIReferenceImplementation/UserControls/EditorUserControl.xaml.cs:
--------------------------------------------------------------------------------
1 | // Copyright @ MyScript. All rights reserved.
2 |
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using Windows.UI.Xaml;
6 | using Windows.UI.Xaml.Input;
7 | using Windows.UI.Core;
8 | using Windows.UI.Popups;
9 | using Windows.System;
10 | using Windows.Graphics.Display;
11 | using Microsoft.Graphics.Canvas;
12 | using Microsoft.Graphics.Canvas.UI.Xaml;
13 |
14 | using MyScript.IInk.Graphics;
15 | using MyScript.IInk.UIReferenceImplementation.Extensions;
16 |
17 | // The User Control item template is documented at https://go.microsoft.com/fwlink/?LinkId=234236
18 | namespace MyScript.IInk.UIReferenceImplementation.UserControls
19 | {
20 | public sealed partial class EditorUserControl
21 | {
22 | public static readonly DependencyProperty EditorProperty =
23 | DependencyProperty.Register("Editor", typeof(Editor), typeof(EditorUserControl),
24 | new PropertyMetadata(default(Editor)));
25 |
26 | public Editor Editor
27 | {
28 | get => GetValue(EditorProperty) as Editor;
29 | set
30 | {
31 | SetValue(EditorProperty, value);
32 | if (!(value is Editor editor))return;
33 | Initialize(Editor);
34 | }
35 | }
36 | }
37 |
38 | public sealed partial class EditorUserControl : IRenderTarget
39 | {
40 | private ImageLoader _loader;
41 | private bool _smartGuideEnabled = true;
42 |
43 | public ImageLoader ImageLoader => _loader;
44 | public SmartGuideUserControl SmartGuide => smartGuide;
45 |
46 | private Layer _renderLayer;
47 |
48 | private uint _nextOffscreenRenderId = 0;
49 | private IDictionary _bitmaps = new Dictionary();
50 |
51 | public bool SmartGuideEnabled
52 | {
53 | get
54 | {
55 | return _smartGuideEnabled;
56 | }
57 |
58 | set
59 | {
60 | EnableSmartGuide(value);
61 | }
62 | }
63 |
64 | private int _pointerId = -1;
65 | private bool _onScroll = false;
66 | private Graphics.Point _lastPointerPosition;
67 | private System.Int64 _eventTimeOffset = 0;
68 |
69 | public EditorUserControl()
70 | {
71 | InitializeComponent();
72 |
73 | var msFromEpoch = System.DateTimeOffset.Now.ToUnixTimeMilliseconds();
74 | var msFromBoot = System.Environment.TickCount;
75 | _eventTimeOffset = msFromEpoch - msFromBoot;
76 | }
77 |
78 | private void Initialize(Editor editor)
79 | {
80 | var engine = editor.Engine;
81 |
82 | var dpiX = Editor?.Renderer?.DpiX ?? 96;
83 | var dpiY = Editor?.Renderer?.DpiY ?? 96;
84 |
85 | var render = editor.Renderer;
86 | _renderLayer = new Layer(renderCanvas, this, render);
87 |
88 | var tempFolder = engine.Configuration.GetString("content-package.temp-folder");
89 | _loader = new ImageLoader(Editor, tempFolder);
90 |
91 | _renderLayer.ImageLoader = _loader;
92 |
93 | float verticalMarginPX = 60;
94 | float horizontalMarginPX = 40;
95 | var verticalMarginMM = 25.4f * verticalMarginPX / dpiY;
96 | var horizontalMarginMM = 25.4f * horizontalMarginPX / dpiX;
97 | engine.Configuration.SetNumber("text.margin.top", verticalMarginMM);
98 | engine.Configuration.SetNumber("text.margin.left", horizontalMarginMM);
99 | engine.Configuration.SetNumber("text.margin.right", horizontalMarginMM);
100 | engine.Configuration.SetNumber("math.margin.top", verticalMarginMM);
101 | engine.Configuration.SetNumber("math.margin.bottom", verticalMarginMM);
102 | engine.Configuration.SetNumber("math.margin.left", horizontalMarginMM);
103 | engine.Configuration.SetNumber("math.margin.right", horizontalMarginMM);
104 | }
105 |
106 | /// Force ink layer to be redrawn
107 | public void Invalidate(LayerType layers)
108 | {
109 | if (!(Editor?.Renderer is Renderer renderer)) return;
110 | Invalidate(renderer, layers);
111 | }
112 |
113 | /// Force ink layer to be redrawn
114 | public void Invalidate(Renderer renderer, LayerType layers)
115 | {
116 | _renderLayer.Update();
117 | }
118 |
119 | /// Force ink layer to be redrawn according region
120 | public void Invalidate(Renderer renderer, int x, int y, int width, int height, LayerType layers)
121 | {
122 | if (width > 0 && height > 0)
123 | _renderLayer?.Update(x, y, width, height);
124 | }
125 |
126 | public bool SupportsOffscreenRendering()
127 | {
128 | return true;
129 | }
130 |
131 | public float GetPixelDensity()
132 | {
133 | var info = DisplayInformation.GetForCurrentView();
134 | return info.RawPixelsPerViewPixel > 0 ? (float)info.RawPixelsPerViewPixel :
135 | info.ResolutionScale != ResolutionScale.Invalid ? (float)info.ResolutionScale / 100.0f : 1.0f;
136 | }
137 |
138 | public uint CreateOffscreenRenderSurface(int width, int height, bool alphaMask)
139 | {
140 | // Use DPI 96 to specify 1:1 dip <-> pixel mapping
141 | CanvasDevice device = CanvasDevice.GetSharedDevice();
142 | CanvasRenderTarget offscreen = new CanvasRenderTarget(device, width, height, 96);
143 |
144 | uint offscreenRenderId = _nextOffscreenRenderId++;
145 | _bitmaps.Add(offscreenRenderId, offscreen);
146 | return offscreenRenderId;
147 | }
148 |
149 | public void ReleaseOffscreenRenderSurface(uint surfaceId)
150 | {
151 | CanvasRenderTarget offscreen;
152 | if (!_bitmaps.TryGetValue(surfaceId, out offscreen))
153 | throw new System.NullReferenceException();
154 |
155 | _bitmaps.Remove(surfaceId);
156 | offscreen.Dispose();
157 | }
158 |
159 | public ICanvas CreateOffscreenRenderCanvas(uint offscreenID)
160 | {
161 | CanvasRenderTarget offscreen;
162 | if ( !_bitmaps.TryGetValue(offscreenID, out offscreen) )
163 | throw new System.NullReferenceException();
164 |
165 | return new Canvas(offscreen.CreateDrawingSession(), this, _loader);
166 | }
167 |
168 | public void ReleaseOffscreenRenderCanvas(ICanvas canvas)
169 | {
170 | // The previously created DrawingSession (in CreateOffscreenRenderCanvas) must be disposed
171 | // before we can ask the offscreen surface (CanvasRenderTarget) to recreate a new one.
172 | // So, we ask the canvas to dispose and set to null its DrawingSession; the canvas should be destroyed soon after.
173 | Canvas canvas_ = (Canvas)canvas;
174 | canvas_.DisposeSession();
175 | }
176 |
177 | public CanvasRenderTarget GetImage(uint offscreenID)
178 | {
179 | CanvasRenderTarget offscreen;
180 | if ( !_bitmaps.TryGetValue(offscreenID, out offscreen) )
181 | throw new System.NullReferenceException();
182 |
183 | return offscreen;
184 | }
185 |
186 |
187 | private void EnableSmartGuide(bool enable)
188 | {
189 | if (_smartGuideEnabled == enable)
190 | return;
191 |
192 | _smartGuideEnabled = enable;
193 |
194 | if (!_smartGuideEnabled && smartGuide != null)
195 | smartGuide.Visibility = Visibility.Collapsed;
196 | }
197 |
198 | public void OnResize(int width, int height)
199 | {
200 | Editor?.SetViewSize(width, height);
201 | }
202 |
203 | /// Resize editor when one canvas size has been changed
204 | private void Canvas_SizeChanged(object sender, SizeChangedEventArgs e)
205 | {
206 | if (sender == renderCanvas)
207 | {
208 | OnResize((int)renderCanvas.ActualWidth, (int)renderCanvas.ActualHeight);
209 | }
210 |
211 | ((CanvasVirtualControl)(sender)).Invalidate();
212 | }
213 |
214 | /// Redrawing Canvas
215 | private void Canvas_OnRegionsInvalidated(CanvasVirtualControl sender, CanvasRegionsInvalidatedEventArgs args)
216 | {
217 | foreach (var region in args.InvalidatedRegions)
218 | {
219 | if (region.Width > 0 && region.Height > 0)
220 | {
221 | var x = (int)System.Math.Floor(region.X);
222 | var y = (int)System.Math.Floor(region.Y);
223 | var width = (int)System.Math.Ceiling(region.X + region.Width) - x;
224 | var height = (int)System.Math.Ceiling(region.Y + region.Height) - y;
225 |
226 | if (sender == renderCanvas)
227 | _renderLayer.OnPaint(x, y, width, height);
228 | }
229 | }
230 | }
231 |
232 | private System.Int64 GetTimestamp(Windows.UI.Input.PointerPoint point)
233 | {
234 | // Convert the timestamp (from boot time) to milliseconds
235 | // and add offset to get the time from EPOCH
236 | return _eventTimeOffset + (System.Int64)(point.Timestamp / 1000);
237 | }
238 |
239 | public int GetPointerId(RoutedEventArgs e)
240 | {
241 | if (e is PointerRoutedEventArgs)
242 | return (int)((PointerRoutedEventArgs)e).Pointer.PointerDeviceType;
243 | else if (e is HoldingRoutedEventArgs)
244 | return (int)((HoldingRoutedEventArgs)e).PointerDeviceType;
245 |
246 | return -1;
247 | }
248 |
249 | [System.Flags]
250 | public enum ContextualActions
251 | {
252 | NONE = 0,
253 | ADD_BLOCK = 1 << 0, /// Add block. See Editor.GetSupportedAddBlockTypes.
254 | REMOVE = 1 << 1, /// Remove selection.
255 | CONVERT = 1 << 2, /// Convert. See Editor.GetSupportedTargetConversionStates.
256 | COPY = 1 << 3, /// Copy selection.
257 | OFFICE_CLIPBOARD = 1 << 4, /// Copy selection to Microsoft Office clipboard.
258 | PASTE = 1 << 5, /// Paste.
259 | IMPORT = 1 << 6, /// Import. See Editor.GetSupportedImportMimeTypes.
260 | EXPORT = 1 << 7, /// Export. See Editor.GetSupportedExportMimeTypes.
261 | FORMAT_TEXT = 1 << 8, /// Change Text blocks format.
262 | SELECTION_MODE = 1 << 9, /// Change selection mode.
263 | SELECTION_TYPE = 1 << 10 /// Change selection type.
264 | }
265 |
266 | public ContextualActions GetAvailableActions(ContentBlock contentBlock)
267 | {
268 | if (contentBlock == null || Editor == null)
269 | return ContextualActions.NONE;
270 |
271 | var part = Editor.Part;
272 | if (part == null)
273 | return ContextualActions.NONE;
274 |
275 | var actions = ContextualActions.NONE;
276 |
277 | using (var rootBlock = Editor.GetRootBlock())
278 | {
279 | var isRoot = contentBlock.Id == rootBlock.Id;
280 | if (!isRoot && (contentBlock.Type == "Container"))
281 | return ContextualActions.NONE;
282 |
283 | var onRawContent = part.Type == "Raw Content";
284 | var onTextDocument = part.Type == "Text Document";
285 |
286 | var isEmpty = Editor.IsEmpty(contentBlock);
287 |
288 | var supportedBlocks = Editor.SupportedAddBlockTypes;
289 | var supportedExports = Editor.GetSupportedExportMimeTypes(onRawContent ? rootBlock : contentBlock);
290 | var supportedImports = Editor.GetSupportedImportMimeTypes(contentBlock);
291 | var supportedStates = Editor.GetSupportedTargetConversionStates(contentBlock);
292 | var supportedFormats = Editor.GetSupportedTextFormats(contentBlock);
293 | var supportedModes = Editor.GetAvailableSelectionModes();
294 | var supportedTypes = Editor.GetAvailableSelectionTypes(contentBlock);
295 |
296 | var hasBlocks = (supportedBlocks != null) && supportedBlocks.Any();
297 | var hasExports = (supportedExports != null) && supportedExports.Any();
298 | var hasImports = (supportedImports != null) && supportedImports.Any();
299 | var hasStates = (supportedStates != null) && supportedStates.Any();
300 | var hasFormats = (supportedFormats != null) && supportedFormats.Any();
301 | var hasModes = (supportedModes != null) && supportedModes.Any();
302 | var hasTypes = (supportedTypes != null) && supportedTypes.Any();
303 |
304 | if (hasBlocks && (!onTextDocument || isRoot))
305 | actions |= ContextualActions.ADD_BLOCK;
306 | if (!isRoot)
307 | actions |= ContextualActions.REMOVE;
308 | if (hasStates && !isEmpty)
309 | actions |= ContextualActions.CONVERT;
310 | if (!onTextDocument || !isRoot)
311 | actions |= ContextualActions.COPY;
312 | if (hasExports && supportedExports.Contains(MimeType.OFFICE_CLIPBOARD))
313 | actions |= ContextualActions.OFFICE_CLIPBOARD;
314 | if (isRoot)
315 | actions |= ContextualActions.PASTE;
316 | if (hasImports)
317 | actions |= ContextualActions.IMPORT;
318 | if (hasExports)
319 | actions |= ContextualActions.EXPORT;
320 | if (hasFormats)
321 | actions |= ContextualActions.FORMAT_TEXT;
322 | if (hasModes)
323 | actions |= ContextualActions.SELECTION_MODE;
324 | if (hasTypes)
325 | actions |= ContextualActions.SELECTION_TYPE;
326 | }
327 |
328 | return actions;
329 | }
330 |
331 | public ContextualActions GetAvailableActions(ContentSelection contentSelection)
332 | {
333 | if (contentSelection == null || Editor == null || Editor.IsEmpty(contentSelection))
334 | return ContextualActions.NONE;
335 |
336 | var part = Editor.Part;
337 | if (part == null)
338 | return ContextualActions.NONE;
339 |
340 | var actions = ContextualActions.NONE;
341 |
342 | var supportedExports = Editor.GetSupportedExportMimeTypes(contentSelection);
343 | var supportedStates = Editor.GetSupportedTargetConversionStates(contentSelection);
344 | var supportedFormats = Editor.GetSupportedTextFormats(contentSelection);
345 | var supportedModes = Editor.GetAvailableSelectionModes();
346 | var supportedTypes = Editor.GetAvailableSelectionTypes(contentSelection);
347 |
348 | var hasExports = (supportedExports != null) && supportedExports.Any();
349 | var hasStates = (supportedStates != null) && supportedStates.Any();
350 | var hasFormats = (supportedFormats != null) && supportedFormats.Any();
351 | var hasModes = (supportedModes != null) && supportedModes.Any();
352 | var hasTypes = (supportedTypes != null) && supportedTypes.Any();
353 |
354 | // Erase
355 | actions |= ContextualActions.REMOVE;
356 | if (hasStates)
357 | actions |= ContextualActions.CONVERT;
358 | // Copy
359 | actions |= ContextualActions.COPY;
360 | if (hasExports && supportedExports.Contains(MimeType.OFFICE_CLIPBOARD))
361 | actions |= ContextualActions.OFFICE_CLIPBOARD;
362 | if (hasExports)
363 | actions |= ContextualActions.EXPORT;
364 | if (hasFormats)
365 | actions |= ContextualActions.FORMAT_TEXT;
366 | if (hasModes)
367 | actions |= ContextualActions.SELECTION_MODE;
368 | if (hasTypes)
369 | actions |= ContextualActions.SELECTION_TYPE;
370 |
371 | return actions;
372 | }
373 |
374 | public void CancelSampling(int pointerId)
375 | {
376 | Editor?.PointerCancel(pointerId);
377 | _pointerId = -1;
378 | }
379 |
380 | private bool HasPart()
381 | {
382 | return Editor?.Part != null;
383 | }
384 |
385 | private void Capture_PointerPressed(object sender, PointerRoutedEventArgs e)
386 | {
387 | var uiElement = sender as UIElement;
388 | var p = e.GetCurrentPoint(uiElement);
389 |
390 | if (!HasPart())
391 | return;
392 |
393 | if (_pointerId != -1)
394 | return;
395 |
396 | // Consider left button only
397 | if ( (!p.Properties.IsLeftButtonPressed) || (p.Properties.PointerUpdateKind != Windows.UI.Input.PointerUpdateKind.LeftButtonPressed) )
398 | return;
399 |
400 | // Capture the pointer to the target.
401 | uiElement?.CapturePointer(e.Pointer);
402 |
403 | try
404 | {
405 | _pointerId = (int)e.Pointer.PointerId;
406 | _lastPointerPosition = new Graphics.Point((float)p.Position.X, (float)p.Position.Y);
407 | _onScroll = false;
408 |
409 | // Send pointer down event to the editor
410 | Editor?.PointerDown((float)p.Position.X, (float)p.Position.Y, GetTimestamp(p), p.Properties.Pressure, e.Pointer.PointerDeviceType.ToNative(), GetPointerId(e));
411 | }
412 | catch (System.Exception ex)
413 | {
414 | if (ex.HResult == (int)MyScript.IInk.ExceptionHResult.POINTER_SEQUENCE_ERROR)
415 | {
416 | // Special case: pointerDown already called, discard previous and retry
417 | Editor?.PointerCancel(GetPointerId(e));
418 | Editor?.PointerDown((float)p.Position.X, (float)p.Position.Y, GetTimestamp(p), p.Properties.Pressure, e.Pointer.PointerDeviceType.ToNative(), GetPointerId(e));
419 | }
420 | else
421 | {
422 | var dlg = new MessageDialog(ex.Message);
423 | var dlgTask = dlg.ShowAsync();
424 | }
425 | }
426 | // Prevent most handlers along the event route from handling the same event again.
427 | e.Handled = true;
428 | }
429 |
430 | private void Capture_PointerMoved(object sender, PointerRoutedEventArgs e)
431 | {
432 | var uiElement = sender as UIElement;
433 | var p = e.GetCurrentPoint(uiElement);
434 |
435 | if (!HasPart())
436 | return;
437 |
438 | if (_pointerId != (int)e.Pointer.PointerId)
439 | return;
440 |
441 | // Ignore pointer move when the pointing device is up
442 | if (!p.IsInContact)
443 | return;
444 |
445 | // Consider left button only
446 | if (!p.Properties.IsLeftButtonPressed)
447 | return;
448 |
449 | var pointerType = e.Pointer.PointerDeviceType.ToNative();
450 | var previousPosition = _lastPointerPosition;
451 | _lastPointerPosition = new Graphics.Point((float)p.Position.X, (float)p.Position.Y);
452 |
453 | var pointerTool = Editor.ToolController.GetToolForType(pointerType);
454 | if (!_onScroll && pointerTool == PointerTool.HAND)
455 | {
456 | var deltaMin = 3.0f;
457 | var deltaX = _lastPointerPosition.X - previousPosition.X;
458 | var deltaY = _lastPointerPosition.Y - previousPosition.Y;
459 |
460 | _onScroll = Editor.IsScrollAllowed() && ((System.Math.Abs(deltaX) > deltaMin) || (System.Math.Abs(deltaY) > deltaMin));
461 |
462 | if (_onScroll)
463 | {
464 | // Entering scrolling mode, cancel previous pointerDown event
465 | Editor?.PointerCancel(GetPointerId(e));
466 | }
467 | }
468 |
469 | if (_onScroll)
470 | {
471 | // Scroll the view
472 | var deltaX = _lastPointerPosition.X - previousPosition.X;
473 | var deltaY = _lastPointerPosition.Y - previousPosition.Y;
474 | Scroll(-deltaX, -deltaY);
475 | }
476 | else
477 | {
478 | var pointList = e.GetIntermediatePoints(uiElement);
479 | if (pointList.Count > 0)
480 | {
481 | var events = new PointerEvent[pointList.Count];
482 |
483 | // Intermediate points are stored in reverse order:
484 | // Revert the list and send the pointer events all at once
485 | int j = 0;
486 | for (int i = pointList.Count - 1; i >= 0; i--)
487 | {
488 | var p_ = pointList[i];
489 | events[j++] = new PointerEvent(PointerEventType.MOVE, (float)p_.Position.X, (float)p_.Position.Y, GetTimestamp(p_), p_.Properties.Pressure, pointerType, GetPointerId(e));
490 | }
491 |
492 | // Send pointer move events to the editor
493 | try
494 | {
495 | Editor?.PointerEvents(events);
496 | }
497 | catch
498 | {
499 | // Don't show error for every move event
500 | }
501 | }
502 | }
503 |
504 | // Prevent most handlers along the event route from handling the same event again.
505 | e.Handled = true;
506 | }
507 |
508 | private void Capture_PointerReleased(object sender, PointerRoutedEventArgs e)
509 | {
510 | var uiElement = sender as UIElement;
511 | var p = e.GetCurrentPoint(uiElement);
512 |
513 | if (!HasPart())
514 | return;
515 |
516 | if (_pointerId != (int)e.Pointer.PointerId)
517 | return;
518 |
519 | // Consider left button only
520 | if ( (p.Properties.IsLeftButtonPressed) || (p.Properties.PointerUpdateKind != Windows.UI.Input.PointerUpdateKind.LeftButtonReleased) )
521 | return;
522 |
523 | var previousPosition = _lastPointerPosition;
524 | _lastPointerPosition = new Graphics.Point((float)p.Position.X, (float)p.Position.Y);
525 |
526 | if (_onScroll)
527 | {
528 | // Scroll the view
529 | var deltaX = _lastPointerPosition.X - previousPosition.X;
530 | var deltaY = _lastPointerPosition.Y - previousPosition.Y;
531 | Scroll(-deltaX, -deltaY);
532 |
533 | // Exiting scrolling mode
534 | _onScroll = false;
535 | }
536 | else
537 | {
538 | // Send pointer up event to the editor
539 | try
540 | {
541 | Editor?.PointerUp((float)p.Position.X, (float)p.Position.Y, GetTimestamp(p), p.Properties.Pressure, e.Pointer.PointerDeviceType.ToNative(), GetPointerId(e));
542 | }
543 | catch
544 | {
545 | // Don't show error for up event
546 | }
547 | }
548 |
549 | _pointerId = -1;
550 |
551 | // Release the pointer captured from the target
552 | uiElement?.ReleasePointerCapture(e.Pointer);
553 |
554 | // Prevent most handlers along the event route from handling the same event again.
555 | e.Handled = true;
556 | }
557 |
558 | private void Capture_PointerCanceled(object sender, PointerRoutedEventArgs e)
559 | {
560 | var uiElement = sender as UIElement;
561 | var p = e.GetCurrentPoint(uiElement);
562 |
563 | if (!HasPart())
564 | return;
565 |
566 | if (_pointerId != (int)e.Pointer.PointerId)
567 | return;
568 |
569 | // When using mouse consider left button only
570 | if (e.Pointer.PointerDeviceType == Windows.Devices.Input.PointerDeviceType.Mouse)
571 | {
572 | if (!p.Properties.IsLeftButtonPressed)
573 | return;
574 | }
575 |
576 | if (_onScroll)
577 | {
578 | // Exiting scrolling mode
579 | _onScroll = false;
580 | }
581 | else
582 | {
583 | // Send pointer cancel event to the editor
584 | Editor.PointerCancel(GetPointerId(e));
585 | }
586 |
587 | _pointerId = -1;
588 |
589 | // Prevent most handlers along the event route from handling the same event again.
590 | e.Handled = true;
591 | }
592 |
593 | private void Capture_PointerWheelChanged(object sender, PointerRoutedEventArgs e)
594 | {
595 | var uiElement = renderCanvas; //sender as UIElement;
596 | var properties = e.GetCurrentPoint(uiElement).Properties;
597 |
598 | if (!HasPart())
599 | return;
600 |
601 | if (properties.IsHorizontalMouseWheel == false)
602 | {
603 | var WHEEL_DELTA = 120;
604 |
605 | var controlDown = CoreWindow.GetForCurrentThread().GetKeyState(VirtualKey.Control).HasFlag(CoreVirtualKeyStates.Down);
606 | var shiftDown = CoreWindow.GetForCurrentThread().GetKeyState(VirtualKey.Shift).HasFlag(CoreVirtualKeyStates.Down);
607 | var wheelDelta = properties.MouseWheelDelta / WHEEL_DELTA;
608 |
609 | if (controlDown)
610 | {
611 | if (wheelDelta > 0)
612 | ZoomIn((uint)wheelDelta);
613 | else if (wheelDelta < 0)
614 | ZoomOut((uint)(-wheelDelta));
615 | }
616 | else
617 | {
618 | var SCROLL_SPEED = 100;
619 | var delta = (float)(-SCROLL_SPEED * wheelDelta);
620 | var deltaX = shiftDown ? delta : 0.0f;
621 | var deltaY = shiftDown ? 0.0f : delta;
622 |
623 | Scroll(deltaX, deltaY);
624 | }
625 | }
626 |
627 | // Prevent most handlers along the event route from handling the same event again.
628 | e.Handled = true;
629 | }
630 |
631 | public void ResetView(bool forceInvalidate)
632 | {
633 | if (!(Editor?.Renderer is Renderer renderer) || !HasPart())
634 | return;
635 |
636 | // Reset view offset and scale
637 | renderer.ViewScale = 1;
638 | renderer.ViewOffset = new Graphics.Point(0, 0);
639 |
640 | // Get new view transform (keep only scale and offset)
641 | var tr = renderer.GetViewTransform();
642 | tr = new Graphics.Transform(tr.XX, tr.YX, 0, tr.XY, tr.YY, 0);
643 |
644 | // Compute new view offset
645 | var offset = new Graphics.Point(0, 0);
646 |
647 | if (Editor.Part.Type == "Raw Content")
648 | {
649 | // Center view on the center of content for "Raw Content" parts
650 | var contentBox = Editor.GetRootBlock().Box;
651 | var contentCenter = new Graphics.Point(contentBox.X + (contentBox.Width * 0.5f), contentBox.Y + (contentBox.Height * 0.5f));
652 |
653 | // From model coordinates to view coordinates
654 | contentCenter = tr.Apply(contentCenter.X, contentCenter.Y);
655 |
656 | var viewCenter = new Graphics.Point(Editor.ViewWidth * 0.5f, Editor.ViewHeight * 0.5f);
657 | offset.X = contentCenter.X - viewCenter.X;
658 | offset.Y = contentCenter.Y - viewCenter.Y;
659 | }
660 | else
661 | {
662 | // Move the origin to the top-left corner of the page for other types of parts
663 | var boxV = Editor.Part.ViewBox;
664 |
665 | offset.X = boxV.X;
666 | offset.Y = boxV.Y;
667 |
668 | // From model coordinates to view coordinates
669 | offset = tr.Apply(offset.X, offset.Y);
670 | }
671 |
672 | // Set new view offset
673 | renderer.ViewOffset = offset;
674 |
675 | if (forceInvalidate)
676 | Invalidate(renderer, LayerType.LayerType_ALL);
677 | }
678 |
679 | public void ZoomIn(uint delta)
680 | {
681 | if (!(Editor?.Renderer is Renderer renderer)) return;
682 | renderer.Zoom((float)delta * (110.0f / 100.0f));
683 | Invalidate(renderer, LayerType.LayerType_ALL);
684 | }
685 |
686 | public void ZoomOut(uint delta)
687 | {
688 | if (!(Editor?.Renderer is Renderer renderer)) return;
689 | renderer.Zoom((float)delta * (100.0f / 110.0f));
690 | Invalidate(renderer, LayerType.LayerType_ALL);
691 | }
692 |
693 | private void Scroll(float deltaX, float deltaY)
694 | {
695 | if (!(Editor?.Renderer is Renderer renderer)) return;
696 | var oldOffset = renderer.ViewOffset;
697 | var newOffset = new Graphics.Point(oldOffset.X + deltaX, oldOffset.Y + deltaY);
698 |
699 | renderer.ViewOffset = newOffset;
700 | Invalidate(renderer, LayerType.LayerType_ALL);
701 | }
702 | }
703 | }
704 |
--------------------------------------------------------------------------------
/UIReferenceImplementation/UserControls/InkToolbar.xaml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
13 |
14 |
15 |
16 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
33 |
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/UIReferenceImplementation/UserControls/InkToolbar.xaml.cs:
--------------------------------------------------------------------------------
1 | // Copyright @ MyScript. All rights reserved.
2 |
3 | using System;
4 | using Windows.Foundation;
5 | using Windows.UI;
6 | using Windows.UI.Input.Inking;
7 | using Windows.UI.Xaml;
8 | using Windows.UI.Xaml.Controls;
9 | using Windows.UI.Xaml.Media;
10 | using MyScript.IInk.UIReferenceImplementation.Extensions;
11 |
12 | namespace MyScript.IInk.UIReferenceImplementation.UserControls
13 | {
14 | public sealed partial class InkToolbar
15 | {
16 | public static readonly DependencyProperty EditorProperty =
17 | DependencyProperty.Register("Editor", typeof(Editor), typeof(InkToolbar),
18 | new PropertyMetadata(default(Editor)));
19 |
20 | public static readonly DependencyProperty IsActivePenEnabledProperty =
21 | DependencyProperty.Register("IsActivePenEnabled", typeof(bool), typeof(InkToolbar),
22 | new PropertyMetadata(true, OnIsActivePenEnabledValueChanged));
23 |
24 | public InkToolbar()
25 | {
26 | InitializeComponent();
27 | }
28 |
29 | ///
30 | ///
31 | ///
32 | public Editor Editor
33 | {
34 | get => GetValue(EditorProperty) as Editor;
35 | set => SetValue(EditorProperty, value);
36 | }
37 |
38 | public bool IsActivePenEnabled
39 | {
40 | get => (bool)GetValue(IsActivePenEnabledProperty);
41 | set => SetValue(IsActivePenEnabledProperty, value);
42 | }
43 |
44 | private static void OnIsActivePenEnabledValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
45 | {
46 | if (!(d is InkToolbar toolbar) || !(toolbar.Editor?.ToolController is ToolController controller)) return;
47 | var isActivePenEnabled = e.NewValue is bool b && b;
48 | var pointerTool = controller.GetToolForType(PointerType.PEN);
49 | controller.SetToolForType(PointerType.TOUCH, isActivePenEnabled ? PointerTool.HAND : pointerTool);
50 | // if active pen is activated and the hand tool is previously selected,
51 | // it will be disabled and the active tool will fall back to the pen tool.
52 | if (isActivePenEnabled && pointerTool == PointerTool.HAND)
53 | toolbar.Toolbar.ActiveTool = toolbar.Toolbar.GetToolButton(InkToolbarTool.BallpointPen);
54 | }
55 |
56 | private void OnActiveToolChanged(Windows.UI.Xaml.Controls.InkToolbar sender, object args)
57 | {
58 | if (!(Editor?.ToolController is ToolController controller)) return;
59 | var tool = sender.ActiveTool;
60 | switch (tool.ToolKind)
61 | {
62 | case InkToolbarTool.BallpointPen:
63 | case InkToolbarTool.Pencil:
64 | OnPenActivated(controller, IsActivePenEnabled);
65 | break;
66 | case InkToolbarTool.Highlighter:
67 | OnHighlighterActivated(controller, IsActivePenEnabled);
68 | break;
69 | case InkToolbarTool.Eraser:
70 | OnEraserActivated(controller, IsActivePenEnabled);
71 | break;
72 | case InkToolbarTool.CustomPen:
73 | break;
74 | case InkToolbarTool.CustomTool:
75 | if (tool == HandTool) OnHandToolActivated(controller);
76 | else if (tool == SelectorTool) OnSelectorToolActivated(controller, IsActivePenEnabled);
77 | break;
78 | default:
79 | throw new ArgumentOutOfRangeException();
80 | }
81 | }
82 |
83 | private void OnEraseAllClicked(Windows.UI.Xaml.Controls.InkToolbar sender, object args)
84 | {
85 | Editor?.Clear();
86 | }
87 |
88 | private void OnInkDrawingAttributesChanged(Windows.UI.Xaml.Controls.InkToolbar sender, object args)
89 | {
90 | Editor?.Apply(sender.InkDrawingAttributes);
91 | }
92 |
93 | private void OnInkToolbarPenButtonLoaded(object sender, RoutedEventArgs e)
94 | {
95 | if (!(sender is InkToolbarPenButton target)) return;
96 | Editor?.Apply(new InkDrawingAttributes
97 | {
98 | Color = target.SelectedBrush is SolidColorBrush brush ? brush.Color : default(Color),
99 | DrawAsHighlighter = target is InkToolbarHighlighterButton,
100 | Size = new Size(target.SelectedStrokeWidth, target.SelectedStrokeWidth)
101 | });
102 | }
103 |
104 | #region On Tool Activated (Eraser, Hand, Highlighter, Pen, Selector)
105 |
106 | private static void OnEraserActivated(ToolController controller, bool isActivePenEnabled)
107 | {
108 | controller.SetToolForType(PointerType.PEN, PointerTool.ERASER);
109 | controller.SetToolForType(PointerType.MOUSE, PointerTool.ERASER);
110 | controller.SetToolForType(PointerType.TOUCH,
111 | isActivePenEnabled ? PointerTool.HAND : PointerTool.ERASER);
112 | }
113 |
114 | private static void OnHandToolActivated(ToolController controller)
115 | {
116 | controller.SetToolForType(PointerType.MOUSE, PointerTool.HAND);
117 | controller.SetToolForType(PointerType.TOUCH, PointerTool.HAND);
118 | controller.SetToolForType(PointerType.PEN, PointerTool.HAND);
119 | }
120 |
121 | private static void OnHighlighterActivated(ToolController controller, bool isActivePenEnabled)
122 | {
123 | controller.SetToolForType(PointerType.PEN, PointerTool.HIGHLIGHTER);
124 | controller.SetToolForType(PointerType.MOUSE, PointerTool.HIGHLIGHTER);
125 | controller.SetToolForType(PointerType.TOUCH,
126 | isActivePenEnabled ? PointerTool.HAND : PointerTool.HIGHLIGHTER);
127 | }
128 |
129 | private static void OnPenActivated(ToolController controller, bool isActivePenEnabled)
130 | {
131 | controller.SetToolForType(PointerType.PEN, PointerTool.PEN);
132 | controller.SetToolForType(PointerType.MOUSE, PointerTool.PEN);
133 | controller.SetToolForType(PointerType.TOUCH,
134 | isActivePenEnabled ? PointerTool.HAND : PointerTool.PEN);
135 | }
136 |
137 | private static void OnSelectorToolActivated(ToolController controller, bool isActivePenEnabled)
138 | {
139 | controller.SetToolForType(PointerType.MOUSE, PointerTool.SELECTOR);
140 | controller.SetToolForType(PointerType.PEN, PointerTool.SELECTOR);
141 | if (!isActivePenEnabled) controller.SetToolForType(PointerType.TOUCH, PointerTool.SELECTOR);
142 | }
143 |
144 | #endregion
145 | }
146 | }
--------------------------------------------------------------------------------
/UIReferenceImplementation/UserControls/SmartGuideUserControl.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
20 |
25 |
26 |
27 |
32 |
35 |
40 |
45 |
50 |
51 |
52 |
53 |
56 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/configurations/Raw Content/drawing.json:
--------------------------------------------------------------------------------
1 | {
2 | "raw-content": {
3 | "line-pattern": "none",
4 | "recognition": {
5 | "types": [ ]
6 | },
7 | "classification": {
8 | "types": [ ]
9 | },
10 | "convert": {
11 | "shape-on-hold": false
12 | },
13 | "shape": {
14 | "snap-axis": [ ]
15 | },
16 | "interactive-blocks": {
17 | "auto-classified": [ ]
18 | },
19 | "eraser": {
20 | "erase-precisely": true,
21 | "dynamic-radius": true
22 | },
23 | "auto-connection": false,
24 | "guides": {
25 | "show": [ ],
26 | "snap": [ ]
27 | },
28 | "pen": {
29 | "gestures": [ ]
30 | },
31 | "rotation": [ "image" ]
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/configurations/Raw Content/text_math_shape.json:
--------------------------------------------------------------------------------
1 | {
2 | "raw-content": {
3 | "configuration": {
4 | "analyzer": {
5 | "bundle": "raw-content2",
6 | "name": "standard"
7 | },
8 | "math": {
9 | "bundle": "math2",
10 | "name": "standard"
11 | }
12 | },
13 | "classification": {
14 | "types": [ "text", "shape", "math", "drawing" ]
15 | },
16 | "recognition": {
17 | "types": [ "text", "shape", "math" ]
18 | },
19 | "convert": {
20 | "shape-on-hold": true
21 | },
22 | "shape": {
23 | "snap-axis": [ ]
24 | },
25 | "eraser": {
26 | "erase-precisely": false,
27 | "dynamic-radius": true
28 | },
29 | "auto-connection": false,
30 | "edge": {
31 | "policy": [ ]
32 | },
33 | "interactive-blocks": {
34 | "auto-classified": [ "text", "math", "shape" ],
35 | "feedback": [ "text", "math" ],
36 | "feedback-hints": [ "text", "math" ]
37 | },
38 | "pen": {
39 | "gestures": [ "scratch-out", "strike-through" ]
40 | },
41 | "line-pattern": "grid",
42 | "guides": {
43 | "show": [ "alignment", "text", "square", "square-inside", "image-aspect-ratio", "rotation" ],
44 | "snap": [ "alignment", "text", "square", "square-inside", "image-aspect-ratio", "rotation" ]
45 | }
46 | },
47 | "convert": {
48 | "convert-on-double-tap": false
49 | },
50 | "math": {
51 | "solver": {
52 | "options": "algebraic",
53 | "numerical-computation": [ "at-right-of-equal-sign", "at-question-mark" ],
54 | "enable-syntactic-correction": false,
55 | "display-implicit-multiply": false,
56 | "auto-variable-management": {
57 | "enable": true,
58 | "scoping-policy": "closest"
59 | }
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/configurations/interactivity.json:
--------------------------------------------------------------------------------
1 | {
2 | "raw-content": {
3 | "classification": {
4 | "types": [ "text", "drawing" ]
5 | },
6 | "recognition": {
7 | "types": [ "text", "math" ]
8 | },
9 | "convert": {
10 | "shape-on-hold": true
11 | },
12 | "shape": {
13 | "snap-axis": [ "triangle", "rectangle", "rhombus", "parallelogram", "ellipse" ]
14 | },
15 | "eraser": {
16 | "erase-precisely": false,
17 | "dynamic-radius": true
18 | },
19 | "auto-connection": true,
20 | "interactive-blocks": {
21 | "feedback": [ "math" ]
22 | },
23 | "pen": {
24 | "gestures": [ "underline", "scratch-out", "strike-through" ]
25 | },
26 | "line-pattern": "grid",
27 | "guides": {
28 | "show": [ "alignment", "text", "square", "square-inside", "image-aspect-ratio", "rotation" ],
29 | "snap": [ "alignment", "text", "square", "square-inside", "image-aspect-ratio", "rotation" ]
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/fonts/MyScriptInter-Bold.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyScript/interactive-ink-examples-uwp/c100f83d8914347839529b1e88dac069d7d4a26a/fonts/MyScriptInter-Bold.otf
--------------------------------------------------------------------------------
/fonts/MyScriptInter-Regular.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyScript/interactive-ink-examples-uwp/c100f83d8914347839529b1e88dac069d7d4a26a/fonts/MyScriptInter-Regular.otf
--------------------------------------------------------------------------------
/fonts/STIXTwoMath-Regular.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyScript/interactive-ink-examples-uwp/c100f83d8914347839529b1e88dac069d7d4a26a/fonts/STIXTwoMath-Regular.otf
--------------------------------------------------------------------------------
/fonts/STIXTwoText-Italic.otf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/MyScript/interactive-ink-examples-uwp/c100f83d8914347839529b1e88dac069d7d4a26a/fonts/STIXTwoText-Italic.otf
--------------------------------------------------------------------------------
/getRecognitionAssets.ps1:
--------------------------------------------------------------------------------
1 | Set-PSDebug -Trace 1
2 | $shell_app=new-object -com shell.application
3 | $destination = $shell_app.namespace("$PSScriptRoot")
4 |
5 |
6 | if (-not[System.IO.File]::Exists("$PSScriptRoot\recognition-assets\conf\diagram.conf") -Or
7 | -not[System.IO.File]::Exists("$PSScriptRoot\recognition-assets\conf\raw-content.conf") -Or
8 | -not[System.IO.File]::Exists("$PSScriptRoot\recognition-assets\conf\raw-content2.conf") -Or
9 | -not[System.IO.File]::Exists("$PSScriptRoot\recognition-assets\conf\math.conf") -Or
10 | -not[System.IO.File]::Exists("$PSScriptRoot\recognition-assets\conf\math2.conf") -Or
11 | -not[System.IO.File]::Exists("$PSScriptRoot\recognition-assets\conf\en_US.conf"))
12 |
13 | {
14 | if ( Test-Path "$PSScriptRoot\recognition-assets")
15 | {
16 | Remove-Item "$PSScriptRoot\recognition-assets\*" -Recurse
17 | }
18 |
19 | # Download myscript-iink-recognition-math.zip
20 | $clnt = new-object System.Net.WebClient
21 | $url = "https://download.myscript.com/iink/recognitionAssets_iink_4.1/myscript-iink-recognition-math.zip"
22 | $file = "$PSScriptRoot\myscript-iink-recognition-math.zip"
23 |
24 | $clnt.DownloadFile($url,$file)
25 |
26 | # Unzip myscript-iink-recognition-math.zip
27 |
28 | $zip_file = $shell_app.namespace($file)
29 | $destination.Copyhere($zip_file.items(),16)
30 | Remove-Item $file
31 |
32 | # Download myscript-iink-recognition-math2.zip
33 |
34 | $clnt = new-object System.Net.WebClient
35 | $url = "https://download.myscript.com/iink/recognitionAssets_iink_4.1/myscript-iink-recognition-math2.zip"
36 | $file = "$PSScriptRoot\myscript-iink-recognition-math2.zip"
37 | $clnt.DownloadFile($url,$file)
38 |
39 | # Unzip myscript-iink-recognition-math2.zip
40 |
41 | $zip_file = $shell_app.namespace($file)
42 | $destination.Copyhere($zip_file.items(),16)
43 | Remove-Item $file
44 |
45 | # Download myscript-iink-recognition-diagram.zip
46 |
47 | $clnt = new-object System.Net.WebClient
48 | $url = "https://download.myscript.com/iink/recognitionAssets_iink_4.1/myscript-iink-recognition-diagram.zip"
49 | $file = "$PSScriptRoot\myscript-iink-recognition-diagram.zip"
50 | $clnt.DownloadFile($url,$file)
51 |
52 | # Unzip myscript-iink-recognition-diagram.zip
53 |
54 | $zip_file = $shell_app.namespace($file)
55 | $destination.Copyhere($zip_file.items(),16)
56 | Remove-Item $file
57 |
58 | # Download myscript-iink-recognition-raw-content.zip
59 |
60 | $clnt = new-object System.Net.WebClient
61 | $url = "https://download.myscript.com/iink/recognitionAssets_iink_4.1/myscript-iink-recognition-raw-content.zip"
62 | $file = "$PSScriptRoot\myscript-iink-recognition-raw-content.zip"
63 | $clnt.DownloadFile($url,$file)
64 |
65 | # Unzip myscript-iink-recognition-raw-content.zip
66 |
67 | $zip_file = $shell_app.namespace($file)
68 | $destination.Copyhere($zip_file.items(),16)
69 | Remove-Item $file
70 |
71 | # Download myscript-iink-recognition-raw-content2.zip
72 |
73 | $clnt = new-object System.Net.WebClient
74 | $url = "https://download.myscript.com/iink/recognitionAssets_iink_4.1/myscript-iink-recognition-raw-content2.zip"
75 | $file = "$PSScriptRoot\myscript-iink-recognition-raw-content2.zip"
76 | $clnt.DownloadFile($url,$file)
77 |
78 | # Unzip myscript-iink-recognition-raw-content2.zip
79 |
80 | $zip_file = $shell_app.namespace($file)
81 | $destination.Copyhere($zip_file.items(),16)
82 | Remove-Item $file
83 |
84 | # Download myscript-iink-recognition-text-en_US.zip
85 |
86 | $clnt = new-object System.Net.WebClient
87 | $url = "https://download.myscript.com/iink/recognitionAssets_iink_4.1/myscript-iink-recognition-text-en_US.zip"
88 | $file = "$PSScriptRoot\myscript-iink-recognition-text-en_US.zip"
89 | $clnt.DownloadFile($url,$file)
90 |
91 | # Unzip myscript-iink-recognition-text-en_US.zip
92 |
93 | $zip_file = $shell_app.namespace($file)
94 | $destination.Copyhere($zip_file.items(),16)
95 | Remove-Item $file
96 | }
97 |
--------------------------------------------------------------------------------