├── OouiWrapper
├── OouiWrapper.cs
├── OouiWrapper.csproj
├── OouiWrapper.sln
├── Properties
│ └── AssemblyInfo.cs
├── TestOouiWrapper.ps1
├── packages.config
└── packages
│ ├── Newtonsoft.Json.10.0.2
│ ├── .signature.p7s
│ ├── LICENSE.md
│ ├── Newtonsoft.Json.10.0.2.nupkg
│ ├── lib
│ │ ├── net20
│ │ │ ├── Newtonsoft.Json.dll
│ │ │ └── Newtonsoft.Json.xml
│ │ ├── net35
│ │ │ ├── Newtonsoft.Json.dll
│ │ │ └── Newtonsoft.Json.xml
│ │ ├── net40
│ │ │ ├── Newtonsoft.Json.dll
│ │ │ └── Newtonsoft.Json.xml
│ │ ├── net45
│ │ │ ├── Newtonsoft.Json.dll
│ │ │ └── Newtonsoft.Json.xml
│ │ ├── netstandard1.0
│ │ │ ├── Newtonsoft.Json.dll
│ │ │ └── Newtonsoft.Json.xml
│ │ ├── netstandard1.3
│ │ │ ├── Newtonsoft.Json.dll
│ │ │ └── Newtonsoft.Json.xml
│ │ ├── portable-net40 sl5 win8 wpa81 wp8
│ │ │ ├── Newtonsoft.Json.dll
│ │ │ └── Newtonsoft.Json.xml
│ │ └── portable-net45 win8 wpa81 wp8
│ │ │ ├── Newtonsoft.Json.dll
│ │ │ └── Newtonsoft.Json.xml
│ └── tools
│ │ └── install.ps1
│ └── Ooui.0.14.16
│ ├── .signature.p7s
│ ├── Icon.png
│ ├── Ooui.0.14.16.nupkg
│ └── lib
│ └── netstandard2.0
│ └── Ooui.dll
├── README.md
├── UIfied.Test
├── MaterialCF.gif
├── MaterialOoui.gif
├── MaterialWPF.gif
├── SimpleTest.gif
├── SimpleTest.ps1
└── UIfiedSample.ps1
├── UIfied
├── Bin
│ ├── Binding.dll
│ ├── ConsoleFramework.dll
│ ├── MaterialDesignColors.dll
│ ├── MaterialDesignThemes.Wpf.dll
│ ├── Newtonsoft.Json.dll
│ ├── Ooui.dll
│ ├── OouiWrapper.dll
│ └── Xaml.dll
├── LICENSE.txt
├── LoadCFBinaries.ps1
├── LoadMaterialWPFBinaries.ps1
├── LoadOouiBinaries.ps1
├── LoadWPFBinaries.ps1
├── UIfied.psd1
├── UIfied.psm1
├── UIfiedBase.ps1
├── UIfiedCFBase.ps1
├── UIfiedDSL.ps1
├── UIfiedMaterialCFBase.ps1
├── UIfiedMaterialOouiBase.ps1
├── UIfiedMaterialWPFBase.ps1
├── UIfiedOouiBase.ps1
└── UIfiedWPFBase.ps1
└── sign-form.png
/OouiWrapper/OouiWrapper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Threading;
6 | using System.Text;
7 | using System.IO;
8 | using Ooui;
9 |
10 | namespace OouiWrapper
11 | {
12 | public class OouiWrapper
13 | {
14 | public Element Frame;
15 | public int Port;
16 | public string Host = UI.Host;
17 | private string Path;
18 | public delegate void OnPublishHandler();
19 | public event OnPublishHandler OnPublish;
20 | private string UploadFolder;
21 |
22 | public OouiWrapper(int port = 8187, string path = "/frame")
23 | {
24 | this.Port = port;
25 | this.Path = path;
26 | this.Frame = new Label { Text = "Press refresh button" };
27 | }
28 | public void Publish()
29 | {
30 | UI.Host = this.Host;
31 | UI.Port = this.Port;
32 | UI.Publish(this.Path, MakeElement);
33 | }
34 | public Element MakeElement()
35 | {
36 | var b = this.MakeFrame();
37 | UI.Publish(this.Path, MakeElement);
38 | return b;
39 | }
40 | public Element MakeFrame()
41 | {
42 | this.OnPublish.Invoke();
43 | return this.Frame;
44 | }
45 | public void PublishFileUpload(string uploadFolder, string actionUrl = "/files/upload")
46 | {
47 | this.UploadFolder = uploadFolder;
48 | UI.Publish("/files", this.CreateFileUploadElement(), true);
49 | UI.PublishCustomResponse(actionUrl, HandleUpload);
50 | }
51 | void HandleUpload(HttpListenerContext context, CancellationToken token)
52 | {
53 |
54 | SaveFile(context.Request.ContentEncoding, GetBoundary(context.Request.ContentType), context.Request.InputStream, this.UploadFolder);
55 |
56 | context.Response.StatusCode = 200;
57 | context.Response.ContentType = "text/html";
58 | using (StreamWriter writer = new StreamWriter(context.Response.OutputStream, Encoding.UTF8))
59 | writer.WriteLine("File Uploaded");
60 |
61 | context.Response.Close();
62 | }
63 | //public void HandleHookableElement(HttpListenerContext listenerContext, CancellationToken token)
64 | //{
65 | // var url = listenerContext.Request.Url;
66 | // var path = url.LocalPath;
67 | // var response = listenerContext.Response;
68 | //
69 | // response.StatusCode = 200;
70 | // response.ContentType = "text/html";
71 | // response.ContentEncoding = Encoding.UTF8;
72 | // var html = Encoding.UTF8.GetBytes(UI.RenderTemplate(path));
73 | // //var html = Encoding.UTF8.GetBytes(MakeFrame()));
74 | // response.ContentLength64 = html.LongLength;
75 | // using (var s = response.OutputStream)
76 | // {
77 | // s.Write(html, 0, html.Length);
78 | // }
79 | // response.Close();
80 | //}
81 | private static String GetBoundary(String ctype)
82 | {
83 | return "--" + ctype.Split(';')[1].Split('=')[1];
84 | }
85 |
86 | private static void SaveFile(Encoding enc, String boundary, Stream input, string uploadFolder)
87 | {
88 | Byte[] boundaryBytes = enc.GetBytes(boundary);
89 | Int32 boundaryLen = boundaryBytes.Length;
90 |
91 | Byte[] buffer = new Byte[1024];
92 | Int32 len = input.Read(buffer, 0, 1024);
93 | Int32 startPos = -1;
94 |
95 | var inputText = System.Text.UTF8Encoding.UTF8.GetString(buffer);
96 | var fileNameBeginPos = inputText.IndexOf("filename=") + "filename=".Length;
97 | var fileNameLen = inputText.Substring(fileNameBeginPos).IndexOf('\n') - 1;
98 | var fileName = inputText.Substring(fileNameBeginPos, fileNameLen).Replace("\"", "");
99 |
100 | using (FileStream output = new FileStream(uploadFolder + System.IO.Path.DirectorySeparatorChar + fileName, FileMode.Create, FileAccess.Write))
101 | {
102 |
103 | // Find start boundary
104 | while (true)
105 | {
106 | if (len == 0)
107 | {
108 | throw new Exception("Start Boundaray Not Found");
109 | }
110 |
111 | startPos = IndexOf(buffer, len, boundaryBytes);
112 | if (startPos >= 0)
113 | {
114 | break;
115 | }
116 | else
117 | {
118 | Array.Copy(buffer, len - boundaryLen, buffer, 0, boundaryLen);
119 | len = input.Read(buffer, boundaryLen, 1024 - boundaryLen);
120 | }
121 | }
122 |
123 | // Skip four lines (Boundary, Content-Disposition, Content-Type, and a blank)
124 | for (Int32 i = 0; i < 4; i++)
125 | {
126 | while (true)
127 | {
128 | if (len == 0)
129 | {
130 | throw new Exception("Preamble not Found.");
131 | }
132 |
133 | startPos = Array.IndexOf(buffer, enc.GetBytes("\n")[0], startPos);
134 | if (startPos >= 0)
135 | {
136 | startPos++;
137 | break;
138 | }
139 | else
140 | {
141 | len = input.Read(buffer, 0, 1024);
142 | }
143 | }
144 | }
145 |
146 | Array.Copy(buffer, startPos, buffer, 0, len - startPos);
147 | len = len - startPos;
148 |
149 | while (true)
150 | {
151 | Int32 endPos = IndexOf(buffer, len, boundaryBytes);
152 | if (endPos >= 0)
153 | {
154 | if (endPos > 0) output.Write(buffer, 0, endPos - 2);
155 | break;
156 | }
157 | else if (len <= boundaryLen)
158 | {
159 | throw new Exception("End Boundaray Not Found");
160 | }
161 | else
162 | {
163 | output.Write(buffer, 0, len - boundaryLen);
164 | Array.Copy(buffer, len - boundaryLen, buffer, 0, boundaryLen);
165 | len = input.Read(buffer, boundaryLen, 1024 - boundaryLen) + boundaryLen;
166 | }
167 | }
168 | }
169 | }
170 |
171 | private static Int32 IndexOf(Byte[] buffer, Int32 len, Byte[] boundaryBytes)
172 | {
173 | for (Int32 i = 0; i <= len - boundaryBytes.Length; i++)
174 | {
175 | Boolean match = true;
176 | for (Int32 j = 0; j < boundaryBytes.Length && match; j++)
177 | {
178 | match = buffer[i + j] == boundaryBytes[j];
179 | }
180 |
181 | if (match)
182 | {
183 | return i;
184 | }
185 | }
186 |
187 | return -1;
188 | }
189 | public Element CreateFileUploadElement(string actionUrl = "/files/upload")
190 | {
191 | var heading = new Heading("Upload Files");
192 | var subtitle = new Paragraph("Upload files to the app");
193 |
194 | var uploadForm = new Form();
195 | uploadForm.Action = actionUrl;
196 | uploadForm.Method = "POST";
197 | uploadForm.EncodingType = "multipart/form-data";
198 | uploadForm.AppendChild(new Input(InputType.File) { Name = "file" });
199 | uploadForm.AppendChild(new Input(InputType.Submit) { Value = "Upload" });
200 |
201 | var app = new Div();
202 | app.AppendChild(heading);
203 | app.AppendChild(subtitle);
204 | app.AppendChild(uploadForm);
205 |
206 | return app;
207 | }
208 | }
209 |
210 | }
211 |
--------------------------------------------------------------------------------
/OouiWrapper/OouiWrapper.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {1CE9B1C6-1C6E-44DF-A9CC-CBF1DF69BFA5}
8 | Library
9 | OouiWrapper
10 | OouiWrapper
11 | v4.7.2
12 | 512
13 | true
14 | true
15 |
16 |
17 | AnyCPU
18 | true
19 | full
20 | false
21 | ..\Bin\
22 | DEBUG;TRACE
23 | prompt
24 | 4
25 |
26 |
27 | AnyCPU
28 | pdbonly
29 | true
30 | bin\Release\
31 | TRACE
32 | prompt
33 | 4
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 | ..\OouiWrapper\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll
42 |
43 |
44 | packages\Ooui.0.14.16\lib\netstandard2.0\Ooui.dll
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
--------------------------------------------------------------------------------
/OouiWrapper/OouiWrapper.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 16
4 | VisualStudioVersion = 16.0.29409.12
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "OouiWrapper", "OouiWrapper.csproj", "{1CE9B1C6-1C6E-44DF-A9CC-CBF1DF69BFA5}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|Any CPU = Debug|Any CPU
11 | Release|Any CPU = Release|Any CPU
12 | EndGlobalSection
13 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
14 | {1CE9B1C6-1C6E-44DF-A9CC-CBF1DF69BFA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15 | {1CE9B1C6-1C6E-44DF-A9CC-CBF1DF69BFA5}.Debug|Any CPU.Build.0 = Debug|Any CPU
16 | {1CE9B1C6-1C6E-44DF-A9CC-CBF1DF69BFA5}.Release|Any CPU.ActiveCfg = Release|Any CPU
17 | {1CE9B1C6-1C6E-44DF-A9CC-CBF1DF69BFA5}.Release|Any CPU.Build.0 = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(SolutionProperties) = preSolution
20 | HideSolutionNode = FALSE
21 | EndGlobalSection
22 | GlobalSection(ExtensibilityGlobals) = postSolution
23 | SolutionGuid = {EF8FDD8B-5F67-432F-B8D3-3513CAA10726}
24 | EndGlobalSection
25 | EndGlobal
26 |
--------------------------------------------------------------------------------
/OouiWrapper/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // La información general de un ensamblado se controla mediante el siguiente
6 | // conjunto de atributos. Cambie estos valores de atributo para modificar la información
7 | // asociada a un ensamblado.
8 | [assembly: AssemblyTitle("ConsoleApp1")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("ConsoleApp1")]
13 | [assembly: AssemblyCopyright("Copyright © 2019")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Si establece ComVisible en false, los tipos de este ensamblado no estarán visibles
18 | // para los componentes COM. Si es necesario obtener acceso a un tipo en este ensamblado desde
19 | // COM, establezca el atributo ComVisible en true en este tipo.
20 | [assembly: ComVisible(false)]
21 |
22 | // El siguiente GUID sirve como id. de typelib si este proyecto se expone a COM.
23 | [assembly: Guid("1ce9b1c6-1c6e-44df-a9cc-cbf1df69bfa5")]
24 |
25 | // La información de versión de un ensamblado consta de los cuatro valores siguientes:
26 | //
27 | // Versión principal
28 | // Versión secundaria
29 | // Número de compilación
30 | // Revisión
31 | //
32 | // Puede especificar todos los valores o usar los valores predeterminados de número de compilación y de revisión
33 | // utilizando el carácter "*", como se muestra a continuación:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/OouiWrapper/TestOouiWrapper.ps1:
--------------------------------------------------------------------------------
1 | dir $PSScriptRoot\..\bin\*.dll | ForEach-Object {
2 | [Reflection.Assembly]::Load([System.IO.File]::ReadAllBytes($_))
3 | }
4 |
5 | $hostWrapper = [OouiWrapper.OouiWrapper]::new()
6 | $hostWrapper.Publish()
7 | $hostWrapper.PublishFileUpload()
8 |
9 | #Add-Member -InputObject $hostWrapper -MemberType NoteProperty -Name sb -Value {[Ooui.Button]::new("hola mundo " + [DateTime]::Now.ToString())}
10 | Add-Member -InputObject $hostWrapper -MemberType NoteProperty -Name sb -Value $hostWrapper
11 |
12 | Register-ObjectEvent -InputObject $hostWrapper -EventName OnPublish -MessageData $hostWrapper -Action {
13 | param ($hostWrapper)
14 | $event.MessageData.Frame = Invoke-Command -ScriptBlock $event.MessageData.sb.CreateFileUploadElement()
15 | }
16 |
--------------------------------------------------------------------------------
/OouiWrapper/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/OouiWrapper/packages/Newtonsoft.Json.10.0.2/.signature.p7s:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/OouiWrapper/packages/Newtonsoft.Json.10.0.2/.signature.p7s
--------------------------------------------------------------------------------
/OouiWrapper/packages/Newtonsoft.Json.10.0.2/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2007 James Newton-King
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/OouiWrapper/packages/Newtonsoft.Json.10.0.2/Newtonsoft.Json.10.0.2.nupkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/OouiWrapper/packages/Newtonsoft.Json.10.0.2/Newtonsoft.Json.10.0.2.nupkg
--------------------------------------------------------------------------------
/OouiWrapper/packages/Newtonsoft.Json.10.0.2/lib/net20/Newtonsoft.Json.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/OouiWrapper/packages/Newtonsoft.Json.10.0.2/lib/net20/Newtonsoft.Json.dll
--------------------------------------------------------------------------------
/OouiWrapper/packages/Newtonsoft.Json.10.0.2/lib/net35/Newtonsoft.Json.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/OouiWrapper/packages/Newtonsoft.Json.10.0.2/lib/net35/Newtonsoft.Json.dll
--------------------------------------------------------------------------------
/OouiWrapper/packages/Newtonsoft.Json.10.0.2/lib/net40/Newtonsoft.Json.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/OouiWrapper/packages/Newtonsoft.Json.10.0.2/lib/net40/Newtonsoft.Json.dll
--------------------------------------------------------------------------------
/OouiWrapper/packages/Newtonsoft.Json.10.0.2/lib/net45/Newtonsoft.Json.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/OouiWrapper/packages/Newtonsoft.Json.10.0.2/lib/net45/Newtonsoft.Json.dll
--------------------------------------------------------------------------------
/OouiWrapper/packages/Newtonsoft.Json.10.0.2/lib/netstandard1.0/Newtonsoft.Json.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/OouiWrapper/packages/Newtonsoft.Json.10.0.2/lib/netstandard1.0/Newtonsoft.Json.dll
--------------------------------------------------------------------------------
/OouiWrapper/packages/Newtonsoft.Json.10.0.2/lib/netstandard1.3/Newtonsoft.Json.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/OouiWrapper/packages/Newtonsoft.Json.10.0.2/lib/netstandard1.3/Newtonsoft.Json.dll
--------------------------------------------------------------------------------
/OouiWrapper/packages/Newtonsoft.Json.10.0.2/lib/portable-net40 sl5 win8 wpa81 wp8/Newtonsoft.Json.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/OouiWrapper/packages/Newtonsoft.Json.10.0.2/lib/portable-net40 sl5 win8 wpa81 wp8/Newtonsoft.Json.dll
--------------------------------------------------------------------------------
/OouiWrapper/packages/Newtonsoft.Json.10.0.2/lib/portable-net45 win8 wpa81 wp8/Newtonsoft.Json.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/OouiWrapper/packages/Newtonsoft.Json.10.0.2/lib/portable-net45 win8 wpa81 wp8/Newtonsoft.Json.dll
--------------------------------------------------------------------------------
/OouiWrapper/packages/Newtonsoft.Json.10.0.2/tools/install.ps1:
--------------------------------------------------------------------------------
1 | param($installPath, $toolsPath, $package, $project)
2 |
3 | # open json.net splash page on package install
4 | # don't open if json.net is installed as a dependency
5 |
6 | try
7 | {
8 | $url = "http://www.newtonsoft.com/json/install?version=" + $package.Version
9 | $dte2 = Get-Interface $dte ([EnvDTE80.DTE2])
10 |
11 | if ($dte2.ActiveWindow.Caption -eq "Package Manager Console")
12 | {
13 | # user is installing from VS NuGet console
14 | # get reference to the window, the console host and the input history
15 | # show webpage if "install-package newtonsoft.json" was last input
16 |
17 | $consoleWindow = $(Get-VSComponentModel).GetService([NuGetConsole.IPowerConsoleWindow])
18 |
19 | $props = $consoleWindow.GetType().GetProperties([System.Reflection.BindingFlags]::Instance -bor `
20 | [System.Reflection.BindingFlags]::NonPublic)
21 |
22 | $prop = $props | ? { $_.Name -eq "ActiveHostInfo" } | select -first 1
23 | if ($prop -eq $null) { return }
24 |
25 | $hostInfo = $prop.GetValue($consoleWindow)
26 | if ($hostInfo -eq $null) { return }
27 |
28 | $history = $hostInfo.WpfConsole.InputHistory.History
29 |
30 | $lastCommand = $history | select -last 1
31 |
32 | if ($lastCommand)
33 | {
34 | $lastCommand = $lastCommand.Trim().ToLower()
35 | if ($lastCommand.StartsWith("install-package") -and $lastCommand.Contains("newtonsoft.json"))
36 | {
37 | $dte2.ItemOperations.Navigate($url) | Out-Null
38 | }
39 | }
40 | }
41 | else
42 | {
43 | # user is installing from VS NuGet dialog
44 | # get reference to the window, then smart output console provider
45 | # show webpage if messages in buffered console contains "installing...newtonsoft.json" in last operation
46 |
47 | $instanceField = [NuGet.Dialog.PackageManagerWindow].GetField("CurrentInstance", [System.Reflection.BindingFlags]::Static -bor `
48 | [System.Reflection.BindingFlags]::NonPublic)
49 |
50 | $consoleField = [NuGet.Dialog.PackageManagerWindow].GetField("_smartOutputConsoleProvider", [System.Reflection.BindingFlags]::Instance -bor `
51 | [System.Reflection.BindingFlags]::NonPublic)
52 |
53 | if ($instanceField -eq $null -or $consoleField -eq $null) { return }
54 |
55 | $instance = $instanceField.GetValue($null)
56 |
57 | if ($instance -eq $null) { return }
58 |
59 | $consoleProvider = $consoleField.GetValue($instance)
60 | if ($consoleProvider -eq $null) { return }
61 |
62 | $console = $consoleProvider.CreateOutputConsole($false)
63 |
64 | $messagesField = $console.GetType().GetField("_messages", [System.Reflection.BindingFlags]::Instance -bor `
65 | [System.Reflection.BindingFlags]::NonPublic)
66 | if ($messagesField -eq $null) { return }
67 |
68 | $messages = $messagesField.GetValue($console)
69 | if ($messages -eq $null) { return }
70 |
71 | $operations = $messages -split "=============================="
72 |
73 | $lastOperation = $operations | select -last 1
74 |
75 | if ($lastOperation)
76 | {
77 | $lastOperation = $lastOperation.ToLower()
78 |
79 | $lines = $lastOperation -split "`r`n"
80 |
81 | $installMatch = $lines | ? { $_.StartsWith("------- installing...newtonsoft.json ") } | select -first 1
82 |
83 | if ($installMatch)
84 | {
85 | $dte2.ItemOperations.Navigate($url) | Out-Null
86 | }
87 | }
88 | }
89 | }
90 | catch
91 | {
92 | try
93 | {
94 | $pmPane = $dte2.ToolWindows.OutputWindow.OutputWindowPanes.Item("Package Manager")
95 |
96 | $selection = $pmPane.TextDocument.Selection
97 | $selection.StartOfDocument($false)
98 | $selection.EndOfDocument($true)
99 |
100 | if ($selection.Text.StartsWith("Attempting to gather dependencies information for package 'Newtonsoft.Json." + $package.Version + "'"))
101 | {
102 | # don't show on upgrade
103 | if (!$selection.Text.Contains("Removed package"))
104 | {
105 | $dte2.ItemOperations.Navigate($url) | Out-Null
106 | }
107 | }
108 | }
109 | catch
110 | {
111 | # stop potential errors from bubbling up
112 | # worst case the splash page won't open
113 | }
114 | }
115 |
116 | # still yolo
--------------------------------------------------------------------------------
/OouiWrapper/packages/Ooui.0.14.16/.signature.p7s:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/OouiWrapper/packages/Ooui.0.14.16/.signature.p7s
--------------------------------------------------------------------------------
/OouiWrapper/packages/Ooui.0.14.16/Icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/OouiWrapper/packages/Ooui.0.14.16/Icon.png
--------------------------------------------------------------------------------
/OouiWrapper/packages/Ooui.0.14.16/Ooui.0.14.16.nupkg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/OouiWrapper/packages/Ooui.0.14.16/Ooui.0.14.16.nupkg
--------------------------------------------------------------------------------
/OouiWrapper/packages/Ooui.0.14.16/lib/netstandard2.0/Ooui.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/OouiWrapper/packages/Ooui.0.14.16/lib/netstandard2.0/Ooui.dll
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # UIfied
2 |
3 | A unified PowerShell DSL for multiple UIs.
4 |
5 | ## Simple DSL
6 |
7 | Write complex UIs the easy way with the UIfied DSL
8 |
9 | $sample = {
10 | $wsb = {
11 | UIWindow -Caption "Title" -Components {
12 | UIStackPanel -Orientation Vertical -Components {
13 | UILabel -Caption "Hello"
14 | UIButton -Caption "Button" -Action {
15 | param($this)
16 | $this.Control.Caption = Get-Date
17 | }
18 | }
19 | }
20 | }
21 | $h = Get-UIHost
22 | $h.ShowFrame($wsb)
23 | }
24 |
25 | Set-UIWpf
26 | Invoke-Command -ScriptBlock $sample
27 |
28 | ## Six UI types supported
29 |
30 | UIFied supports six UI flavors
31 |
32 | - Windows: UIfied creates WPF UIs.
33 | - Console: UIfied uses [ConsoleFramework](https://github.com/elw00d/consoleframework) for console UIs.
34 | - Web: UIfied web support is based on [Ooui](https://github.com/praeclarum/Ooui).
35 | - Material Windows: WPF with Material Design flavor based on [MaterialDesignInXamlToolkit](https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit).
36 | - Material Console: Console with Material Design flavor. You must install [Literation Mono Nerd Font Complete Mono Windows Compatible.ttf](https://github.com/ryanoasis/nerd-fonts) fonts for correct icon visualization.
37 | - Material Web: Web with Material Design flavor
38 |
39 | Write once and use it accross differents UIs. You can switch the target UI framework by simply using a command.
40 |
41 | Set-UICF # Switch to console UI
42 | Set-UIWPF # Switch to Windows Presentation Foundation UI
43 | Set-UIOoui # Switch to Web UI
44 | Set-UIMaterialCF # Switch to Material Design console UI
45 | Set-UIMaterialWPF # Switch to Material Design WPF UI
46 | Set-UIMaterialOoui # Switch to Material Design Web UI
47 |
48 | 
49 |
50 | ## Controls
51 |
52 | We have implemented these controls:
53 |
54 | - Button
55 | - CheckBox
56 | - Label
57 | - List
58 | - ListColumn
59 | - ListItem
60 | - RadioButton
61 | - RadioGroup
62 | - StackPanel
63 | - TabControl
64 | - TabItem
65 | - TextBox
66 | - Modal
67 | - Timer
68 | - DatePicker
69 | - TimePicker
70 | - Browser
71 | - Autocomplete
72 | - Icon
73 | - Card
74 | - Image
75 | - TextEditor
76 | - Expander
77 | - ComboBox
78 | - Expander
79 |
80 | ## Screenshots
81 |
82 | Material Design console sample
83 | 
84 |
85 | Material Design windows sample
86 | 
87 |
88 | Material Design web sample
89 | 
90 |
--------------------------------------------------------------------------------
/UIfied.Test/MaterialCF.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/UIfied.Test/MaterialCF.gif
--------------------------------------------------------------------------------
/UIfied.Test/MaterialOoui.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/UIfied.Test/MaterialOoui.gif
--------------------------------------------------------------------------------
/UIfied.Test/MaterialWPF.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/UIfied.Test/MaterialWPF.gif
--------------------------------------------------------------------------------
/UIfied.Test/SimpleTest.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/UIfied.Test/SimpleTest.gif
--------------------------------------------------------------------------------
/UIfied.Test/SimpleTest.ps1:
--------------------------------------------------------------------------------
1 | Import-Module UIfied
2 |
3 | $sample = {
4 | $wsb = {
5 | UIWindow -Caption "Title" -Components {
6 | UIStackPanel -Orientation Vertical -Components {
7 | UILabel -Caption "Hello"
8 | UIButton -Caption "Button" -Action {
9 | param($this)
10 | $this.Control.Caption = Get-Date
11 | }
12 | }
13 | }
14 | }
15 | $h = Get-UIHost
16 | $h.ShowFrame($wsb)
17 | }
18 |
19 | Set-UIWpf
20 | Invoke-Command -ScriptBlock $sample
21 |
22 | #Set-UICF
23 | #Invoke-Command -ScriptBlock $sample
24 | #
25 | #Set-UIOoui
26 | #Invoke-Command -ScriptBlock $sample
27 |
--------------------------------------------------------------------------------
/UIfied.Test/UIfiedSample.ps1:
--------------------------------------------------------------------------------
1 |
2 | Import-Module "$PSScriptRoot\..\UIfied"
3 |
4 | $wsb = {
5 | UIWindow -Caption "My Title" -Loaded {
6 | param ($this)
7 | $this.Form.Caption = $this.Form.Caption + " Loaded at " + (Get-Date).ToString() + " " + $PID
8 | } -Components {
9 | UIStackPanel -Orientation Vertical -Components {
10 | UITabControl -Components {
11 | UITabItem -Caption "Controls" -Components {
12 | UIStackPanel -Orientation Horizontal -Components {
13 | UIStackPanel -Orientation Vertical -Components {
14 | UICard -Caption "Labels" -Components {
15 | UILabel -Caption "This is a Label" -Name MyLabel
16 | }
17 | UICard -Caption Buttons -Components {
18 | UILabel -Caption "Button:" -Name ButtonLabel
19 | UIButton -Caption "My Button" -Name MyButton -Action {
20 | param($this)
21 | $this.Form.ButtonLabel.Caption = Get-Date
22 | $this.Form.MyButton.Icon = (Get-UIIcon -Kind "add")
23 | $this.Form.MyCombo.Text = "1"
24 | } -Icon (UIIcon -Kind "delete")
25 | }
26 | UICard -Caption TextBoxes -Components {
27 | UILabel -Caption "TextBox:" -Name TextBoxLabel
28 | UITextBox -Name MyTextBox -Change {
29 | param($this)
30 | $this.Form.TextBoxLabel.Caption = $this.Control.Text
31 | }
32 | UILabel -Caption "TextAlignment"
33 | UITextBox -TextAlignment Right
34 | UILabel -Caption "Pattern"
35 | UITextBox -TextAlignment Right -Text "0" -DefaultText "0" -Pattern '^\d+$'
36 | UILabel -Caption "Integer"
37 | UIInteger
38 | UILabel -Caption "Double"
39 | UIDouble
40 | }
41 | UICard -Caption ComboBox -Components {
42 | UIComboBox -Text 2 -Name MyCombo -Components {
43 | Get-UIComboBoxItem -Id 1 -Caption Hello
44 | Get-UIComboBoxItem -Id 2 -Caption GoodBy
45 | } -Change {
46 | param($this)
47 | $this.Form.TextBoxLabel.Caption = $this.Control.Text
48 | }
49 | }
50 | }
51 | UIStackPanel -Orientation Vertical -Components {
52 | UICard -Caption Pickers -Components {
53 | UILabel -Caption "DatePicker:"
54 | UIDatePicker -Value ([DateTime]::Today) -Name MyDatePicker
55 | UILabel -Caption "TimePicker:"
56 | UITimePicker -Value "15:27" -Name MyTimePicker
57 | }
58 | UICard -Caption Toogles -Components {
59 | UILabel -Caption "RadioButton:"
60 | UIRadioButton -Caption "Fish"
61 | UILabel -Caption "CheckBox:"
62 | UICheckBox -Caption "Ketchup"
63 | }
64 | UICard -Caption TextEditor -Components {
65 | UILabel -Caption "TextEditor:"
66 | UITextEditor -Text "Change this text`nLine2" -Height 5 -Width 30
67 | }
68 | UICard -Caption Password -Components {
69 | UIPassword -Change {
70 | param($this)
71 | $this.Form.TextBoxLabel.Caption = $this.Control.Text
72 | }
73 | }
74 | }
75 | }
76 | }
77 | UITabItem -Caption "Containers" -Components {
78 | UIStackPanel -Orientation Horizontal -Components {
79 | UICard -Caption "Lists" -Components {
80 | UIList -Name Grid -Columns {
81 | UIListColumn -Title "Column 1"
82 | UIListColumn -Title "Column 2"
83 | } -Items {
84 | UIListItem -Components {
85 | UILabel -Caption "Cell 1,1"
86 | UICheckBox -Caption "Cell 1,2"
87 | }
88 | UIListItem -Components {
89 | UILabel -Caption "Cell 2,1"
90 | UICheckBox -Caption "Cell 2,2"
91 | }
92 | UIListItem -Components {
93 | UILabel -Caption "Cell 3,1"
94 | UICheckBox -Caption "Cell 3,2"
95 | }
96 | }
97 | }
98 | UICard -Caption "RadioGroups" -Components {
99 | UIRadioGroup -Components {
100 | UIRadioButton -Caption "Fish"
101 | UIRadioButton -Caption "Meat"
102 | }
103 | }
104 | UICard -Caption "DropDownMenus" -Components {
105 | UIDropDownMenu -Caption "my dropdown" -Components {
106 | UIMenuItem -Caption "Menu 1" -Action {
107 | param($this)
108 | $this.Control.Caption = Get-Date
109 | }
110 | UIMenuItem -Caption "Menu 2" -Action {
111 | param($this)
112 | $this.Control.Caption = Get-Date
113 | }
114 | }
115 | }
116 | #UICard -Caption "Expanders" -Components {
117 | # UIExpander -Caption "My expander" -Components {
118 | # UILabel -Caption "Expander content"
119 | # }
120 | #}
121 | }
122 | UIStackPanel -Orientation Horizontal -Components {
123 | UICard -Caption "Autocompletes" -Components {
124 | UILabel -Caption "Press down key to view options"
125 | UIAutoComplete -Text "AB" -ItemsRequested {
126 | param($this)
127 | Get-UIAutoCompleteItem -Id "id1" -Text ($this.Text + " sample")
128 | Get-UIAutoCompleteItem -Id "id2" -Text ([DateTime]::Now.ToString())
129 | Get-UIAutoCompleteItem -Id "id3" -Text ($this.Text + " sample2")
130 | Get-UIAutoCompleteItem -Id "id4" -Text ([DateTime]::Now.ToString())
131 | }
132 | }
133 | UICard -Caption Cards -Name MyCard -Icon (UIIcon -Kind delete) -Components {
134 | UILabel -Caption "Card body content here"
135 | UIButton -Caption "Change" -Action {
136 | param($this)
137 | $this.Form.MyCard.Caption = "Hello Card"
138 | $this.Form.MyCard.Icon = (Get-UIIcon -Kind add)
139 | }
140 | }
141 | UICard -Caption "Modals" -Components {
142 | UILabel -Caption "Click to show modal form"
143 | UIButton -Caption "Show" -Action {
144 | param($this)
145 | $this.Form.MyModal.Show()
146 | }
147 | UIModal -Name MyModal -Title "MY TITLE" -Components {
148 | UIStackPanel -Orientation Vertical -Components {
149 | UICheckBox -Caption "Ketchup"
150 | UICheckBox -Caption "Mayo"
151 | UIButton -Caption "Hide" -Action {
152 | param($this)
153 | $this.Form.MyModal.Hide()
154 | }
155 | }
156 | }
157 | }
158 | }
159 | }
160 | UITabItem -Caption "Browser" -Components {
161 | UIBrowser -Name Browser -Columns {
162 | UIListColumn -Title "Id" -Name Id
163 | UIListColumn -Title "Description" -Name Description
164 | } -Edit {
165 | param($this)
166 | $this.Form.ButtonLabel.Caption = $this.Control.CurrentRow | ConvertTo-Json
167 | } -AddNew {
168 | param($this)
169 | $this.Control.Data += @{Id = "dd"; Description = Get-Date }
170 | $this.Control.Refresh()
171 | } -Data @(
172 | 1..203 | ForEach-Object { @{Id = $_; Description = "Desc $_ jkdf kjafsd j fdas jfas jfas djaf sj "} }
173 | ) -PageRows 10
174 | }
175 | UITabItem -Caption "Others" -Components {
176 | UIStackPanel -Orientation Horizontal -Components {
177 | UICard -Caption "Images" -Components {
178 | UILabel -Caption "Image samples"
179 | UIDropDownMenu -Caption "Select Image" -Components {
180 | UIMenuItem -Caption "PowerShell Logo" -Action {
181 | param($this)
182 | $this.Form.ImageSource.Text = "https://deow9bq0xqvbj.cloudfront.net/image-logo/1769310/powershell.png"
183 | }
184 | UIMenuItem -Caption "Android logo" -Action {
185 | param($this)
186 | $this.Form.ImageSource.Text = "https://logovector.net/wp-content/uploads/2010/06/291431-android-2-logo.png"
187 | }
188 | UIMenuItem -Caption "Apple logo" -Action {
189 | param($this)
190 | $this.Form.ImageSource.Text = "http://cdn.wccftech.com/wp-content/uploads/2013/09/Apple-logo1.jpg"
191 | }
192 | }
193 | UILabel -Caption "Image source"
194 | UITextBox -Name ImageSource
195 | UIButton -Caption "Show" -Action {
196 | param($this)
197 | $this.Form.MyImage.Source = $this.Form.ImageSource.Text
198 | }
199 | UIImage -Name MyImage -Width 300
200 | }
201 | UICard -Caption Timers -Components {
202 | UILabel -Caption "Timer:" -Name TimerLabel
203 | UITimer -Name Timer -Elapsed {
204 | param ($this)
205 | $this.Form.TimerLabel.Caption = Get-Date
206 | }
207 | UIButton -Caption "Run" -Name TimerStart -Action {
208 | param($this)
209 | $this.Form.Timer.Start()
210 | $this.Control.Enable = $false
211 | $this.Form.TimerStop.Enable = $true
212 | }
213 | UIButton -Caption "Stop" -Name TimerStop -Action {
214 | param($this)
215 | $this.Form.Timer.Stop()
216 | $this.Control.Enable = $false
217 | $this.Form.TimerStart.Enable = $true
218 | }
219 | }
220 | UICard -Caption "FileUpload" -Components {
221 | UIFileUpload -Caption "File Upload"
222 | }
223 | }
224 | }
225 | }
226 | }
227 | }
228 | }
229 |
230 | Set-UIOoui
231 |
232 | $h = Get-UIHost
233 | #cls
234 | $h.ShowFrame($wsb)
235 |
236 |
--------------------------------------------------------------------------------
/UIfied/Bin/Binding.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/UIfied/Bin/Binding.dll
--------------------------------------------------------------------------------
/UIfied/Bin/ConsoleFramework.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/UIfied/Bin/ConsoleFramework.dll
--------------------------------------------------------------------------------
/UIfied/Bin/MaterialDesignColors.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/UIfied/Bin/MaterialDesignColors.dll
--------------------------------------------------------------------------------
/UIfied/Bin/MaterialDesignThemes.Wpf.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/UIfied/Bin/MaterialDesignThemes.Wpf.dll
--------------------------------------------------------------------------------
/UIfied/Bin/Newtonsoft.Json.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/UIfied/Bin/Newtonsoft.Json.dll
--------------------------------------------------------------------------------
/UIfied/Bin/Ooui.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/UIfied/Bin/Ooui.dll
--------------------------------------------------------------------------------
/UIfied/Bin/OouiWrapper.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/UIfied/Bin/OouiWrapper.dll
--------------------------------------------------------------------------------
/UIfied/Bin/Xaml.dll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/UIfied/Bin/Xaml.dll
--------------------------------------------------------------------------------
/UIfied/LICENSE.txt:
--------------------------------------------------------------------------------
1 | UIfied
2 |
3 | Copyright (c) Microsoft Corporation
4 |
5 | All rights reserved.
6 |
7 | MIT License
8 |
9 | Permission is hereby granted, free of charge, to any person obtaining a copy
10 | of this software and associated documentation files (the ""Software""), to deal
11 | in the Software without restriction, including without limitation the rights
12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | copies of the Software, and to permit persons to whom the Software is
14 | furnished to do so, subject to the following conditions:
15 |
16 | The above copyright notice and this permission notice shall be included in all
17 | copies or substantial portions of the Software.
18 |
19 | THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 | SOFTWARE.
--------------------------------------------------------------------------------
/UIfied/LoadCFBinaries.ps1:
--------------------------------------------------------------------------------
1 | [Reflection.Assembly]::Load([System.IO.File]::ReadAllBytes("$PSScriptRoot\Bin\Binding.dll"))
2 | [Reflection.Assembly]::Load([System.IO.File]::ReadAllBytes("$PSScriptRoot\Bin\ConsoleFramework.dll"))
3 | [Reflection.Assembly]::Load([System.IO.File]::ReadAllBytes("$PSScriptRoot\Bin\Xaml.dll"))
4 |
5 | Add-Type -AssemblyName System.Drawing
6 |
--------------------------------------------------------------------------------
/UIfied/LoadMaterialWPFBinaries.ps1:
--------------------------------------------------------------------------------
1 | Add-Type -AssemblyName PresentationFramework
2 | [Reflection.Assembly]::Load([System.IO.File]::ReadAllBytes("$PSScriptRoot\Bin\MaterialDesignColors.dll"))
3 | [Reflection.Assembly]::Load([System.IO.File]::ReadAllBytes("$PSScriptRoot\Bin\MaterialDesignThemes.Wpf.dll"))
--------------------------------------------------------------------------------
/UIfied/LoadOouiBinaries.ps1:
--------------------------------------------------------------------------------
1 | [Reflection.Assembly]::Load([System.IO.File]::ReadAllBytes("$PSScriptRoot\Bin\Newtonsoft.Json.dll"))
2 | [Reflection.Assembly]::Load([System.IO.File]::ReadAllBytes("$PSScriptRoot\Bin\Ooui.dll"))
3 | [Reflection.Assembly]::Load([System.IO.File]::ReadAllBytes("$PSScriptRoot\Bin\OouiWrapper.dll"))
4 |
--------------------------------------------------------------------------------
/UIfied/LoadWPFBinaries.ps1:
--------------------------------------------------------------------------------
1 | Add-Type -AssemblyName PresentationFramework
--------------------------------------------------------------------------------
/UIfied/UIfied.psd1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/UIfied/UIfied.psd1
--------------------------------------------------------------------------------
/UIfied/UIfied.psm1:
--------------------------------------------------------------------------------
1 | . "$PSScriptRoot\UIfiedBase.ps1"
2 | . "$PSScriptRoot\UIfiedDSL.ps1"
3 | . "$PSScriptRoot\LoadWpfBinaries.ps1"
4 | . "$PSScriptRoot\UIfiedWpfBase.ps1"
5 | . "$PSScriptRoot\LoadCfBinaries.ps1"
6 | . "$PSScriptRoot\UIfiedCfBase.ps1"
7 | . "$PSScriptRoot\LoadOouiBinaries.ps1"
8 | . "$PSScriptRoot\UIfiedOouiBase.ps1"
9 | . "$PSScriptRoot\UIfiedMaterialOouiBase.ps1"
10 | . "$PSScriptRoot\LoadMaterialWPFBinaries.ps1"
11 | . "$PSScriptRoot\UIfiedMaterialCFBase.ps1"
12 | . "$PSScriptRoot\UIfiedMaterialWPFBase.ps1"
13 |
--------------------------------------------------------------------------------
/UIfied/UIfiedBase.ps1:
--------------------------------------------------------------------------------
1 | using namespace System.Collections.Generic
2 | using namespace System.Management.Automation.Language
3 |
4 | #region UI Type selection
5 |
6 | enum UIType {
7 | WPF
8 | CF
9 | Ooui
10 | MaterialWPF
11 | MaterialOoui
12 | MaterialCF
13 | }
14 |
15 | class UIConfig {
16 | static [UIType] $UIType = [UIType]::MaterialWPF
17 | }
18 |
19 | function Set-UIType {
20 | [CmdletBinding(SupportsShouldProcess)]
21 | param (
22 | [UIType] $Type
23 | )
24 | if ($PSCmdlet.ShouldProcess('TARGET')) {
25 | [UIConfig]::UIType = $Type
26 | }
27 | }
28 |
29 | function Set-UICF {
30 | [CmdletBinding(SupportsShouldProcess)]
31 | param (
32 | )
33 | Set-UIType -Type ([UIType]::CF)
34 | }
35 |
36 | function Set-UIWPF {
37 | [CmdletBinding(SupportsShouldProcess)]
38 | param (
39 | )
40 | Set-UIType -Type ([UIType]::WPF)
41 | }
42 |
43 | function Set-UIOoui {
44 | [CmdletBinding(SupportsShouldProcess)]
45 | param (
46 | )
47 | Set-UIType -Type ([UIType]::Ooui)
48 | }
49 |
50 | function Set-UIMaterialWPF {
51 | [CmdletBinding(SupportsShouldProcess)]
52 | param (
53 | )
54 | Set-UIType -Type ([UIType]::MaterialWPF)
55 | }
56 |
57 | function Set-UIMaterialOoui {
58 | [CmdletBinding(SupportsShouldProcess)]
59 | param (
60 | )
61 | Set-UIType -Type ([UIType]::MaterialOoui)
62 | }
63 |
64 | function Set-UIMaterialCF {
65 | [CmdletBinding(SupportsShouldProcess)]
66 | param (
67 | )
68 | Set-UIType -Type ([UIType]::MaterialCF)
69 | }
70 |
71 | #endregion
72 |
73 | #region UI Constructs
74 |
75 | class UIElement {
76 | hidden [ScriptBlock] $AddNativeUIChild = { param ([UIElement] $element) }
77 | hidden [ScriptBlock] $RemoveNativeUIChild = { param ([UIElement] $element) }
78 | hidden [ScriptBlock] $ShowError = { param ([Object] $errorObject) }
79 | hidden [int] $MaxErrors = 3
80 | hidden [Object] $NativeUI = $null
81 | [List[UIElement]] $Children = [List[UIElement]]::new()
82 | [WindowBase] $Form = $null
83 | [UIElement] $Parent = $null
84 | [String] $Name = ""
85 |
86 | UIElement() {
87 | }
88 |
89 | [void] AddChild([UIElement] $element) {
90 | $this.Children.Add($element)
91 | $element.SetForm($this.Form)
92 | $element.SetParent($this)
93 | Invoke-Command -ScriptBlock $this.AddNativeUIChild -ArgumentList $element
94 | }
95 |
96 | [void] RemoveChild([UIElement] $element) {
97 | Invoke-Command -ScriptBlock $this.RemoveNativeUIChild -ArgumentList $element
98 | $this.Children.Remove($element) | Out-Null
99 | }
100 |
101 | hidden [void] SetForm([WindowBase] $form) {
102 | if ($null -ne $form) {
103 | $this.Form = $form
104 | $this.Children | ForEach-Object {
105 | $_.SetForm($form)
106 | Add-Member -InputObject $_.NativeUI -Name Form -MemberType NoteProperty -Value $form
107 | }
108 | if ($this.Name -ne "") {
109 | $nameMember = Get-Member -InputObject $form -Name $this.Name -MemberType NoteProperty
110 | if ($null -eq $nameMember) {
111 | Add-Member -InputObject $form -Name $this.Name -MemberType NoteProperty -Value $this
112 | }
113 | }
114 | }
115 | }
116 |
117 | hidden [void] SetParent([UIElement] $parent) {
118 | if ($null -ne $parent) {
119 | $this.Parent = $parent
120 | }
121 | }
122 |
123 | hidden [void] WrapProperty([String] $elementPropertyName, [String] $nativeUIProperty) {
124 | $this.WrapProperty($elementPropertyName, $nativeUIProperty, "NativeUI")
125 | }
126 |
127 | hidden [void] WrapProperty([String] $elementPropertyName, [String] $nativeUIProperty, [String] $nativeUIName) {
128 | if (-not $this.IsValidName($elementPropertyName) -or -not $this.IsValidName($nativeUIProperty) -or -not $this.IsValidName($nativeUIName)) {
129 | return
130 | }
131 | Add-Member -InputObject $this -Name $elementPropertyName -MemberType ScriptProperty `
132 | -Value ([ScriptBlock]::Create("`$this.$nativeUIName.$nativeUIProperty")) `
133 | -SecondValue ([ScriptBlock]::Create("`$this.$nativeUIName.$nativeUIProperty = `$args[0]"))
134 | }
135 |
136 | hidden [void] WrapNegatedProperty([String] $elementPropertyName, [String] $nativeUIProperty) {
137 | if (-not $this.IsValidName($elementPropertyName) -or -not $this.IsValidName($nativeUIProperty)) {
138 | return
139 | }
140 | Add-Member -InputObject $this -Name $elementPropertyName -MemberType ScriptProperty `
141 | -Value ([ScriptBlock]::Create("-not `$this.NativeUI.$nativeUIProperty")) `
142 | -SecondValue ([ScriptBlock]::Create("`$this.NativeUI.$nativeUIProperty = -not `$args[0]"))
143 | }
144 |
145 | hidden [void] SetNativeUI([Object] $nativeUI) {
146 | $this.NativeUI = $nativeUI
147 | Add-Member -InputObject $NativeUI -Name Control -MemberType NoteProperty -Value $this -Force
148 | Add-Member -InputObject $this -Name Control -MemberType NoteProperty -Value $this -Force
149 | }
150 |
151 | hidden [bool] IsValidScript([ScriptBlock] $scriptBlock) {
152 | $isValid = $true
153 | $commands = $scriptBlock.Ast.FindAll({ param ($o) $o -is [CommandAst] }, $true)
154 | $commands | ForEach-Object {
155 | $commandName = $_.CommandElements[0].Value
156 | $command = Get-Command -Name $commandName -ErrorAction SilentlyContinue
157 | if ($null -eq $command) {
158 | $isValid = $false
159 | }
160 | }
161 | return $isValid
162 | }
163 |
164 | hidden [void] AddProperty([String]$propertyName) {
165 | if (-not $this.IsValidName($propertyName)) {
166 | return
167 | }
168 | $memberName = "_$propertyName"
169 | Add-Member -InputObject $this -Name $memberName -MemberType NoteProperty -Value {}
170 | Add-Member -InputObject $this -Name $propertyName -MemberType ScriptProperty -Value (
171 | [ScriptBlock]::Create("`$this.$memberName")
172 | ) -SecondValue (
173 | [ScriptBlock]::Create("`$this.$memberName = `$args[0]")
174 | )
175 | }
176 |
177 | hidden [void] AddScriptBlockProperty([String]$propertyName) {
178 | if (-not $this.IsValidName($propertyName)) {
179 | return
180 | }
181 | $memberName = "_$propertyName"
182 | Add-Member -InputObject $this -Name $memberName -MemberType NoteProperty -Value {}
183 | Add-Member -InputObject $this -Name $propertyName -MemberType ScriptProperty -Value (
184 | [ScriptBlock]::Create("`$this.$memberName")
185 | ) -SecondValue (
186 | [ScriptBlock]::Create("
187 | if (`$this.IsValidScript(`$args[0])) {
188 | `$this.$memberName = `$args[0]
189 | } else {
190 | `$this.$memberName = {}
191 | `$this.Visible = `$false
192 | }
193 | ")
194 | )
195 | }
196 |
197 | hidden [bool] IsValidName([String]$name) {
198 | return ($name -match '(^[a-zA-Z_$][a-zA-Z_$0-9]*$)')
199 | }
200 |
201 | hidden [void] InvokeTrappableCommand([ScriptBlock] $ScriptBlock, [Object[]] $ArgumentList) {
202 | try {
203 | Invoke-Command -ScriptBlock $ScriptBlock -ArgumentList $ArgumentList
204 | } catch {
205 | $Global:SyncHash.Errors += $_
206 | Invoke-Command -ScriptBlock $this.ShowError -ArgumentList $_
207 | if ($Global:SyncHash.Errors.Count -gt $this.MaxErrors) {
208 | $this.Form.Close()
209 | }
210 | }
211 | }
212 |
213 | [void] AddNoteProperty([String]$propertyName, $value) {
214 | if (-not $this.IsValidName($propertyName)) {
215 | return
216 | }
217 | Add-Member -InputObject $this -Name $propertyName -MemberType NoteProperty -Value $value
218 | }
219 | }
220 |
221 | class WindowBase : UIElement {
222 |
223 | WindowBase() {
224 | $this.Form = $this
225 | }
226 |
227 | [void] Close() {
228 | $this.NativeUI.Close()
229 | }
230 | }
231 |
232 | class UIHost {
233 |
234 | [void] ShowFrame([WindowBase]$window) {
235 | }
236 |
237 | }
238 |
239 | enum Orientation {
240 | Horizontal
241 | Vertical
242 | }
243 |
244 | enum TextAlignment {
245 | Left
246 | Right
247 | }
248 |
249 | class ListItem {
250 | [List[UIElement]] $Children = [List[UIElement]]::new()
251 |
252 | ListItem() {
253 | }
254 |
255 | [void] AddChild([UIElement] $element) {
256 | $this.Children.Add($element)
257 | }
258 |
259 | [void] RemoveChild([UIElement] $element) {
260 | $this.Children.Remove($element)
261 | }
262 | }
263 |
264 | class AutoCompleteItem {
265 | [String] $Id
266 | [String] $Text
267 | }
268 |
269 | #endregion
270 |
271 | #region UI Icons
272 |
273 | class IconStrinfy {
274 | static [bool] $ShowIcon = $true
275 |
276 | hidden static $Icons = @{
277 | menu = [string] [char] 02261 # 62542
278 | add = [string] [char] 62541
279 | edit = [string] [char] 61504
280 | delete = [string] [char] 63061
281 | clear = [string] [char] 62567
282 | calendar_today = [string] [char] 62957
283 | query_builder = [string] [char] 63055
284 | left_semi_circle = [string] [char] 57526
285 | right_semi_circle = [string] [char] 57524
286 | first_page = [string] [char] 64255
287 | chevron_left = [string] [char] 61523
288 | chevron_right = [string] [char] 61524
289 | chevron_up = [string] [char] 61559
290 | chevron_down = [string] [char] 61560
291 | last_page = [string] [char] 64256
292 | radio_button_checked = [string] [char] 64611
293 | radio_button_unchecked = [string] [char] 64612
294 | check_box = [string] [char] 62510
295 | check_box_outlined_blank = [string] [char] 64609
296 | keyboard_arrow_down = [string] [char] 63035
297 | keyboard_arrow_up = [string] [char] 63038
298 | }
299 |
300 | static [String] ToIconString([String] $kindName) {
301 | if ([IconStrinfy]::ShowIcon) {
302 | return [IconStrinfy]::Icons."$kindName"
303 | } else {
304 | return ""
305 | }
306 | }
307 | }
308 |
309 | enum IconPosition {
310 | Left
311 | Right
312 | }
313 |
314 | #endregion
315 |
316 | #region UI Utilities
317 |
318 | function Set-UIControlValue {
319 | param (
320 | $Object,
321 | $Form,
322 | $ControlPrefix = ""
323 | )
324 | $properties = Get-Member -InputObject $Object -MemberType Properties
325 | $properties | ForEach-Object {
326 | $propertyName = $_.Name
327 | $controlName = $ControlPrefix + $propertyName
328 | $control = $Form."$controlName"
329 | if ($control -ne $null) {
330 | $controlProperties = Get-Member -InputObject $control -MemberType Properties
331 | if ($controlProperties.Name -contains "Text") {
332 | $control.Text = $Object."$propertyName"
333 | } elseif ($controlProperties.Name -contains "Value") {
334 | $control.Value = $Object."$propertyName"
335 | }
336 | }
337 | }
338 | }
339 |
340 | function Get-UIControlValue {
341 | param (
342 | $Object,
343 | $Form,
344 | $ControlPrefix = ""
345 | )
346 | $properties = Get-Member -InputObject $Object -MemberType Properties
347 | $properties | ForEach-Object {
348 | $propertyName = $_.Name
349 | $controlName = $ControlPrefix + $propertyName
350 | $control = $Form."$controlName"
351 | if ($control -ne $null) {
352 | $controlProperties = Get-Member -InputObject $control -MemberType Properties
353 | if ($controlProperties.Name -contains "Text") {
354 | $Object."$propertyName" = $control.Text
355 | } elseif ($controlProperties.Name -contains "Value") {
356 | $Object."$propertyName" = $control.Value
357 | }
358 | }
359 | }
360 | $Object
361 | }
362 |
363 | function Get-UIMethod {
364 | param (
365 | [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
366 | [Object] $InputObject,
367 | [Parameter(Position = 0, Mandatory = $true)]
368 | [String] $Name,
369 | [Parameter(Position = 1)]
370 | [ScriptBlock] $ScriptBlock = { }
371 | )
372 | process {
373 | Add-Member -InputObject $InputObject -MemberType ScriptMethod -Name $Name -Value $ScriptBlock | Out-Null
374 | $InputObject
375 | }
376 | }
377 |
378 | function Get-UIProperty {
379 | param (
380 | [Parameter(Mandatory = $true, ValueFromPipeline = $true)]
381 | [Object] $InputObject,
382 | [Parameter(Position = 0, Mandatory = $true)]
383 | [String] $Name,
384 | [ScriptBlock] $Get = { },
385 | [ScriptBlock] $Set = { }
386 | )
387 | process {
388 | Add-Member -InputObject $InputObject -Name $Name -MemberType ScriptProperty -Value $Get -SecondValue $Set | Out-Null
389 | $InputObject
390 | }
391 | }
392 |
393 | function Add-UIChild {
394 | param (
395 | [Parameter(ValueFromPipeline=$true, Mandatory=$true)]
396 | [UIElement] $Child,
397 | [Parameter(Mandatory=$true)]
398 | [UIElement] $Target
399 | )
400 | process {
401 | $Target.AddChild($Child)
402 | }
403 | }
404 |
405 | function Remove-UIChild {
406 | param (
407 | [Parameter(ValueFromPipeline=$true, Mandatory=$true)]
408 | [UIElement] $Child,
409 | [Parameter(Mandatory=$true)]
410 | [UIElement] $Target
411 | )
412 | process {
413 | $Target.RemoveChild($Child)
414 | }
415 | }
416 |
417 | #endregion
--------------------------------------------------------------------------------
/UIfied/UIfiedDSL.ps1:
--------------------------------------------------------------------------------
1 | using namespace System.Collections.Generic
2 | using namespace System.Management.Automation.Language
3 |
4 | function Get-UIHost {
5 | param (
6 | [UIType] $UIType = [UIConfig]::UIType
7 | )
8 | New-Object ($UIType.ToString() + "Host")
9 | }
10 |
11 | function Get-UIWindow {
12 | param (
13 | [UIType] $UIType = [UIConfig]::UIType,
14 | [ScriptBlock] $Loaded = {},
15 | [ScriptBlock] $Components = {},
16 | [String] $Caption = ""
17 | )
18 | $window = New-Object ($UIType.ToString() + "Window")
19 | $window.Loaded = $Loaded
20 | $window.Caption = $Caption
21 | $childElements = Invoke-Command -ScriptBlock $Components
22 | $childElements | ForEach-Object {
23 | $window.AddChild($_)
24 | }
25 | $window.OnLoaded()
26 | $window
27 | }
28 |
29 | function Get-UIIcon {
30 | param (
31 | [UIType] $UIType = [UIConfig]::UIType,
32 | [String] $Kind = "",
33 | [String] $Name = ""
34 | )
35 | $icon = New-Object ($UIType.ToString() + "Icon")
36 | $icon.Kind = $Kind
37 | $icon.Name = $Name
38 | $icon
39 | }
40 |
41 | function Get-UIButton {
42 | param (
43 | [UIType] $UIType = [UIConfig]::UIType,
44 | [ScriptBlock] $Action = {},
45 | $Icon = $null,
46 | [String] $Caption = "",
47 | [String] $Name = ""
48 | )
49 | $button = New-Object ($UIType.ToString() + "Button")
50 | $button.Action = $Action
51 | $button.Icon = $Icon
52 | $button.Caption = $Caption
53 | $button.Name = $Name
54 | $button
55 | }
56 |
57 | function Get-UIStackPanel {
58 | param (
59 | [UIType] $UIType = [UIConfig]::UIType,
60 | [Orientation] $Orientation = [Orientation]::Vertical,
61 | [ScriptBlock] $Components = {},
62 | [String] $Name = ""
63 | )
64 | $stackPanel = New-Object ($UIType.ToString() + "StackPanel")
65 | $stackPanel.Orientation = $Orientation
66 | $stackPanel.Name = $Name
67 | $childElements = Invoke-Command -ScriptBlock $Components
68 | $childElements | ForEach-Object {
69 | $stackPanel.AddChild($_)
70 | }
71 | $stackPanel
72 | }
73 |
74 | function Get-UILabel {
75 | param (
76 | [UIType] $UIType = [UIConfig]::UIType,
77 | [String] $Caption = "",
78 | [String] $Name = ""
79 | )
80 | $label = New-Object ($UIType.ToString() + "Label")
81 | $label.Caption = $Caption
82 | $label.Name = $Name
83 | $label
84 | }
85 |
86 | function Get-UITextBox {
87 | param (
88 | [UIType] $UIType = [UIConfig]::UIType,
89 | [ScriptBlock] $Change = {},
90 | [String] $Text = "",
91 | [TextAlignment] $TextAlignment = [TextAlignment]::Left,
92 | [String] $Pattern = "",
93 | [String] $DefaultText = "",
94 | [String] $Name = ""
95 | )
96 | $textBox = New-Object ($UIType.ToString() + "TextBox")
97 | $textBox.Change = $Change
98 | $textBox.Text = $Text
99 | $textBox.TextAlignment = $TextAlignment
100 | $textBox.Pattern = $Pattern
101 | $textBox.DefaultText = $DefaultText
102 | $textBox.Name = $Name
103 | $textBox
104 | }
105 |
106 | function Get-UIPassword {
107 | param (
108 | [UIType] $UIType = [UIConfig]::UIType,
109 | [ScriptBlock] $Change = {},
110 | [String] $Text = "",
111 | [String] $Pattern = "",
112 | [String] $DefaultText = "",
113 | [String] $Name = ""
114 | )
115 | $password = New-Object ($UIType.ToString() + "Password")
116 | $password.Change = $Change
117 | $password.Text = $Text
118 | $password.Pattern = $Pattern
119 | $password.DefaultText = $DefaultText
120 | $password.Name = $Name
121 | $password
122 | }
123 |
124 | function Get-UICheckBox {
125 | param (
126 | [UIType] $UIType = [UIConfig]::UIType,
127 | [ScriptBlock] $Click = {},
128 | [Boolean] $IsChecked = $false,
129 | [String] $Caption = "",
130 | [String] $Name = ""
131 | )
132 | $checkBox = New-Object ($UIType.ToString() + "CheckBox")
133 | $checkBox.Click = $Click
134 | $checkBox.IsChecked = $IsChecked
135 | $checkBox.Caption = $Caption
136 | $checkBox.Name = $Name
137 | $checkBox
138 | }
139 |
140 | function Get-UIRadioButton {
141 | param (
142 | [UIType] $UIType = [UIConfig]::UIType,
143 | [ScriptBlock] $Click = {},
144 | [Boolean] $IsChecked = $false,
145 | [String] $Caption = "",
146 | [String] $Name = ""
147 | )
148 | $radioButton = New-Object ($UIType.ToString() + "RadioButton")
149 | $radioButton.Click = $Click
150 | $radioButton.IsChecked = $IsChecked
151 | $radioButton.Caption = $Caption
152 | $radioButton.Name = $Name
153 | $radioButton
154 | }
155 |
156 | function Get-UIRadioGroup {
157 | param (
158 | [UIType] $UIType = [UIConfig]::UIType,
159 | [ScriptBlock] $Components = {},
160 | [String] $Name = ""
161 | )
162 | $radioGroup = New-Object ($UIType.ToString() + "RadioGroup")
163 | $radioGroup.Name = $Name
164 | $childElements = Invoke-Command -ScriptBlock $Components
165 | $childElements | ForEach-Object {
166 | $radioGroup.AddChild($_)
167 | }
168 | $radioGroup
169 | }
170 |
171 | function Get-UIList {
172 | param (
173 | [UIType] $UIType = [UIConfig]::UIType,
174 | [ScriptBlock] $Columns = {},
175 | [ScriptBlock] $Items = {},
176 | [String] $Name = ""
177 | )
178 | $list = New-Object ($UIType.ToString() + "List")
179 | $list.Name = $Name
180 | $columnElements = Invoke-Command -ScriptBlock $Columns
181 | $columnElements | ForEach-Object {
182 | $list.AddColumn($_)
183 | }
184 | $itemElements = Invoke-Command -ScriptBlock $Items
185 | $itemElements | ForEach-Object {
186 | $list.AddItem($_)
187 | }
188 | $list
189 | }
190 |
191 | function Get-UIListColumn {
192 | param (
193 | [UIType] $UIType = [UIConfig]::UIType,
194 | [String] $Title = "",
195 | [String] $Name = ""
196 | )
197 | $listColumn = New-Object ($UIType.ToString() + "ListColumn")
198 | $listColumn.Name = $Name
199 | $listColumn.Title = $Title
200 | $listColumn
201 | }
202 |
203 | function Get-UIListItem {
204 | param (
205 | [UIType] $UIType = [UIConfig]::UIType,
206 | [ScriptBlock] $Components = {},
207 | [String] $Name = ""
208 | )
209 | $listItem = New-Object ListItem
210 | $childElements = Invoke-Command -ScriptBlock $Components
211 | $childElements | ForEach-Object {
212 | $listItem.AddChild($_)
213 | }
214 | $listItem
215 | }
216 |
217 | function Get-UITabItem {
218 | param (
219 | [UIType] $UIType = [UIConfig]::UIType,
220 | [ScriptBlock] $Components = {},
221 | [String] $Caption = "",
222 | [String] $Name = ""
223 | )
224 | $tabItem = New-Object ($UIType.ToString() + "TabItem")
225 | $tabItem.Caption = $Caption
226 | $tabItem.Name = $Name
227 | $childElements = Invoke-Command -ScriptBlock $Components
228 | $childElements | ForEach-Object {
229 | $tabItem.AddChild($_)
230 | }
231 | $tabItem
232 | }
233 |
234 | function Get-UITabControl {
235 | param (
236 | [UIType] $UIType = [UIConfig]::UIType,
237 | [ScriptBlock] $Components = {},
238 | [String] $Name = ""
239 | )
240 | $tabControl = New-Object ($UIType.ToString() + "TabControl")
241 | $tabControl.Name = $Name
242 | $childElements = Invoke-Command -ScriptBlock $Components
243 | $childElements | ForEach-Object {
244 | $tabControl.AddChild($_)
245 | }
246 | $tabControl
247 | }
248 |
249 | function Get-UIModal {
250 | param (
251 | [UIType] $UIType = [UIConfig]::UIType,
252 | [String] $Title = "",
253 | [ScriptBlock] $Components = {},
254 | [String] $Name = ""
255 | )
256 | $modal = New-Object ($UIType.ToString() + "Modal")
257 | $modal.Name = $Name
258 | $modal.Title = $Title
259 | $childElements = Invoke-Command -ScriptBlock $Components
260 | $childElements | ForEach-Object {
261 | $modal.AddChild($_)
262 | }
263 | $modal
264 | }
265 |
266 | function Get-UITimer {
267 | param (
268 | [UIType] $UIType = [UIConfig]::UIType,
269 | [ScriptBlock] $Elapsed = {},
270 | [double] $Interval = 1000,
271 | [String] $Name = ""
272 | )
273 | $timer = New-Object ($UIType.ToString() + "Timer")
274 | $timer.Elapsed = $Elapsed
275 | $timer.Interval = $Interval
276 | $timer.Name = $Name
277 | $timer
278 | }
279 |
280 | function Get-UIDatePicker {
281 | param (
282 | [UIType] $UIType = [UIConfig]::UIType,
283 | [ScriptBlock] $Change = {},
284 | [DateTime] $Value = [DateTime]::Today,
285 | [String] $Name = ""
286 | )
287 | $datePicker = New-Object ($UIType.ToString() + "DatePicker")
288 | $datePicker.Change = $Change
289 | $datePicker.Value = $Value
290 | $datePicker.Name = $Name
291 | $datePicker
292 | }
293 |
294 | function Get-UITimePicker {
295 | param (
296 | [UIType] $UIType = [UIConfig]::UIType,
297 | [ScriptBlock] $Change = {},
298 | [String] $Value = "00:00",
299 | [String] $Name = ""
300 | )
301 | $timePicker = New-Object ($UIType.ToString() + "TimePicker")
302 | $timePicker.Change = $Change
303 | $timePicker.Value = $Value
304 | $timePicker.Name = $Name
305 | $timePicker
306 | }
307 |
308 | function Get-UIBrowser {
309 | param (
310 | [UIType] $UIType = [UIConfig]::UIType,
311 | [ScriptBlock] $Columns = {},
312 | [Object[]] $Data = [Object[]] @(),
313 | [int] $PageRows = 10,
314 | [ScriptBlock] $AddNew = {},
315 | [ScriptBlock] $Edit = {},
316 | [ScriptBlock] $Delete = {},
317 | [String] $Name = ""
318 | )
319 | $browser = New-Object ($UIType.ToString() + "Browser")
320 | $browser.Name = $Name
321 | $columnElements = Invoke-Command -ScriptBlock $Columns
322 | $columnElements | ForEach-Object {
323 | $browser.AddColumn($_)
324 | }
325 | $browser.Data = $Data
326 | $browser.PageRows = $PageRows
327 | $browser.CreateList()
328 | $browser.Refresh()
329 | $browser.AddNew = $AddNew
330 | $browser.Edit = $Edit
331 | $browser.Delete = $Delete
332 | $browser
333 | }
334 |
335 | function Get-UIMenuItem {
336 | param (
337 | [UIType] $UIType = [UIConfig]::UIType,
338 | [ScriptBlock] $Action = {},
339 | [String] $Caption = "",
340 | [String] $Name = ""
341 | )
342 | $menuItem = New-Object ($UIType.ToString() + "MenuItem")
343 | $menuItem.Action = $Action
344 | $menuItem.Caption = $Caption
345 | $menuItem.Name = $Name
346 | $menuItem
347 | }
348 |
349 | function Get-UIDropDownMenu {
350 | param (
351 | [UIType] $UIType = [UIConfig]::UIType,
352 | [String] $Caption = "",
353 | [ScriptBlock] $Components = {},
354 | [String] $Name = ""
355 | )
356 | $dropDownMenu = New-Object ($UIType.ToString() + "DropDownMenu")
357 | $dropDownMenu.Caption = $Caption
358 | $dropDownMenu.Name = $Name
359 | $childElements = Invoke-Command -ScriptBlock $Components
360 | $childElements | ForEach-Object {
361 | $dropDownMenu.AddChild($_)
362 | }
363 | $dropDownMenu
364 | }
365 |
366 | function Get-UIAutoComplete {
367 | param (
368 | [UIType] $UIType = [UIConfig]::UIType,
369 | [ScriptBlock] $ItemsRequested = {param($this) "sample" },
370 | [String] $Text = "",
371 | [String] $Name = ""
372 | )
373 | $autoComplete = New-Object ($UIType.ToString() + "AutoComplete")
374 | #$autoComplete.Text = $Text
375 | $autoComplete.Name = $Name
376 | $autoComplete.ItemsRequested = $ItemsRequested
377 | $autoComplete
378 | }
379 |
380 | function Get-UIAutoCompleteItem {
381 | param (
382 | [String] $Id,
383 | [String] $Text
384 | )
385 | [AutoCompleteItem] @{ Id = $Id; Text = $Text }
386 | }
387 |
388 | function Get-UICard {
389 | param (
390 | [UIType] $UIType = [UIConfig]::UIType,
391 | $Icon = (Get-UIIcon -Kind add),
392 | [String] $Caption = "",
393 | [ScriptBlock] $Components = {},
394 | [String] $Name = ""
395 | )
396 | $card = New-Object ($UIType.ToString() + "Card")
397 | $card.Icon = $Icon
398 | $card.Caption = $Caption
399 | $card.Name = $Name
400 | $childElements = Invoke-Command -ScriptBlock $Components
401 | $childElements | ForEach-Object {
402 | $card.AddChild($_)
403 | }
404 | $card
405 | }
406 |
407 | function Get-UIImage {
408 | param (
409 | [UIType] $UIType = [UIConfig]::UIType,
410 | [String] $Name = "",
411 | [String] $Source = "",
412 | [int] $Width = 50
413 | )
414 | $image = New-Object ($UIType.ToString() + "Image")
415 | if ($Source -ne "") {
416 | $image.Source = $Source
417 | }
418 | $image.Name = $Name
419 | $image.Width = $Width
420 | $image
421 | }
422 |
423 | function Get-UITextEditor {
424 | param (
425 | [UIType] $UIType = [UIConfig]::UIType,
426 | [String] $Text = "",
427 | [Int] $Height = 20,
428 | [Int] $Width = 60,
429 | [String] $Name = ""
430 | )
431 | $textEditor = New-Object ($UIType.ToString() + "TextEditor")
432 | $textEditor.Text = $Text
433 | $textEditor.Name = $Name
434 | $textEditor.Height = $Height
435 | $textEditor.Width = $Width
436 | $textEditor
437 | }
438 |
439 | function Get-UIExpander {
440 | param (
441 | [UIType] $UIType = [UIConfig]::UIType,
442 | [ScriptBlock] $Components = {},
443 | [String] $Caption = "",
444 | [String] $Name = ""
445 | )
446 | $expander = New-Object ($UIType.ToString() + "Expander")
447 | $expander.Caption = $Caption
448 | $expander.Name = $Name
449 | $childElements = Invoke-Command -ScriptBlock $Components
450 | $childElements | ForEach-Object {
451 | $expander.AddChild($_)
452 | }
453 | $expander
454 | }
455 |
456 | function Get-UIInteger {
457 | param (
458 | [UIType] $UIType = [UIConfig]::UIType,
459 | [ScriptBlock] $Change = {},
460 | [String] $Text = "0",
461 | [String] $Name = ""
462 | )
463 | $integer = New-Object ($UIType.ToString() + "Integer")
464 | $integer.Change = $Change
465 | $integer.Text = $Text
466 | $integer.Name = $Name
467 | $integer
468 | }
469 |
470 | function Get-UIDouble {
471 | param (
472 | [UIType] $UIType = [UIConfig]::UIType,
473 | [ScriptBlock] $Change = {},
474 | [String] $Text = "0.00",
475 | [String] $Name = ""
476 | )
477 | $double = New-Object ($UIType.ToString() + "Double")
478 | $double.Change = $Change
479 | $double.Text = $Text
480 | $double.Name = $Name
481 | $double
482 | }
483 |
484 | function Get-UIComboBoxItem {
485 | param (
486 | [String] $Id = "",
487 | [String] $Caption = ""
488 | )
489 | $comboBoxItem = New-Object ($UIType.ToString() + "ComboBoxItem")
490 | $comboBoxItem.Id = $Id
491 | $comboBoxItem.Caption = $Caption
492 | $comboBoxItem
493 | }
494 |
495 | function Get-UIComboBox {
496 | param (
497 | [UIType] $UIType = [UIConfig]::UIType,
498 | [ScriptBlock] $Change = {},
499 | [String] $Text = "",
500 | [ScriptBlock] $Components = {},
501 | [String] $Name = ""
502 | )
503 | $comboBox = New-Object ($UIType.ToString() + "ComboBox")
504 | $comboBox.Name = $Name
505 | $comboBox.Change = $Change
506 | $comboBox.Text = $Text
507 | $childElements = Invoke-Command -ScriptBlock $Components
508 | $childElements | ForEach-Object {
509 | $comboBox.AddChild($_)
510 | }
511 | $comboBox
512 | }
513 |
514 | function Get-UIFileUpload {
515 | param (
516 | [UIType] $UIType = [UIConfig]::UIType,
517 | [String] $Caption = "",
518 | [String] $Name = ""
519 | )
520 | $fileUpload = New-Object ($UIType.ToString() + "FileUpload")
521 | $fileUpload.Name = $Name
522 | $fileUpload.Caption = $Caption
523 | $fileUpload
524 | }
--------------------------------------------------------------------------------
/UIfied/UIfiedMaterialCFBase.ps1:
--------------------------------------------------------------------------------
1 | using namespace System.Collections.Generic
2 | using namespace System.Reflection
3 | using namespace ConsoleFramework
4 | using namespace ConsoleFramework.Core
5 | using namespace ConsoleFramework.Native
6 | using namespace ConsoleFramework.Controls
7 | using namespace ConsoleFramework.Events
8 | using namespace ConsoleFramework.Rendering
9 |
10 | # Font Creation https://www.calligraphr.com/
11 |
12 | class MaterialCFHost : CFHost {
13 | }
14 |
15 | class MaterialCFWindow : CFWindow {
16 |
17 | MaterialCFWindow() {
18 | [CFCustomPanel]::DefaultBackgroundColor = [color]::White
19 | }
20 | }
21 |
22 | class MaterialCFStackPanel : CFStackPanel {
23 | }
24 |
25 | class MaterialCFLabel : CFLabel {
26 |
27 | MaterialCFLabel() {
28 | $this.NativeUI.Color = [Color]::DarkGray
29 | }
30 | }
31 |
32 | class MaterialCFIcon : CFIcon {
33 | }
34 |
35 | class MaterialCFButton : CFButton {
36 |
37 | MaterialCFButton() {
38 | $this.NativeUI.Style = "Primary"
39 | }
40 | }
41 |
42 | class MaterialCFTextBox : CFTextBox {
43 |
44 | MaterialCFTextBox() {
45 | $this.NativeUI.Style = "Flat"
46 | }
47 | }
48 |
49 | class MaterialCFPassword : CFTextBox {
50 |
51 | MaterialCFPassword() {
52 | $this.NativeUI.Style = "FlatPassword"
53 | }
54 | }
55 |
56 | class MaterialCFCheckBox : CFCheckBox {
57 |
58 | MaterialCFCheckBox() {
59 | $this.NativeUI.Style = "Flat"
60 | }
61 | }
62 |
63 | class MaterialCFRadioButton : CFRadioButton {
64 |
65 | MaterialCFRadioButton() {
66 | $this.NativeUI.Style = "Flat"
67 | }
68 | }
69 |
70 | class MaterialCFRadioGroup : CFRadioGroup {
71 | }
72 |
73 | class MaterialCFList : CFList {
74 |
75 | MaterialCFList() {
76 | $this.NativeUI.BackgroundColor = [color]::White
77 | }
78 | }
79 |
80 | class MaterialCFListColumn : CFListColumn {
81 | }
82 |
83 | class MaterialCFTabItem : CFTabItem {
84 | }
85 |
86 | class MaterialCFTabControl : CFTabControl {
87 |
88 | MaterialCFTabControl() {
89 | $this.NativeUI.Style = "Flat"
90 | }
91 | }
92 |
93 | class MaterialCFModal : CFModal {
94 | }
95 |
96 | class MaterialCFTimer : CFTimer {
97 | }
98 |
99 | class MaterialCFDatePicker : CFDatePicker {
100 |
101 | MaterialCFDatePicker() {
102 | $this.NativeUI.Style = "Flat"
103 | }
104 | }
105 |
106 | class MaterialCFTimePicker : CFTimePicker {
107 |
108 | MaterialCFTimePicker() {
109 | $this.NativeUI.Style = "Flat"
110 | }
111 | }
112 |
113 | class MaterialCFBrowser : CFBrowser {
114 |
115 | [void] StyleEditionButtons([CFButton] $editButton, [CFButton] $deleteButton, [int] $rowIndex) {
116 | $editButton.Icon = [MaterialCFIcon] @{ Kind = "edit" }
117 | $editButton.NativeUI.Style = "Flat"
118 | $editButton.NativeUI.ForegroundColor = [Color]::DarkGreen
119 |
120 | $deleteButton.Icon = [MaterialCFIcon] @{ Kind = "delete" }
121 | $deleteButton.NativeUI.Style = "Flat"
122 | $deleteButton.NativeUI.ForegroundColor = [Color]::Red
123 |
124 | $editButton.NativeUI.MaxWidth = 5
125 | $deleteButton.NativeUI.MaxWidth = 5
126 | }
127 |
128 | [void] StyleComponents() {
129 | $this.FirstButton.Icon = [MaterialCFIcon] @{ Kind = "first_page" }
130 | $this.FirstButton.NativeUI.Style = "Flat"
131 | $this.FirstButton.NativeUI.ForegroundColor = [Color]::Magenta
132 |
133 | $this.PreviousButton.Icon = [MaterialCFIcon] @{ Kind = "chevron_left" }
134 | $this.PreviousButton.NativeUI.Style = "Flat"
135 | $this.PreviousButton.NativeUI.ForegroundColor = [Color]::Magenta
136 |
137 | $this.NextButton.Icon = [MaterialCFIcon] @{ Kind = "chevron_right" }
138 | $this.NextButton.NativeUI.Style = "Flat"
139 | $this.NextButton.NativeUI.ForegroundColor = [Color]::Magenta
140 |
141 | $this.LastButton.Icon = [MaterialCFIcon] @{ Kind = "last_page" }
142 | $this.LastButton.NativeUI.Style = "Flat"
143 | $this.LastButton.NativeUI.ForegroundColor = [Color]::Magenta
144 |
145 | $this.AddNewButton.Icon = [MaterialCFIcon] @{ Kind = "add" }
146 | $this.AddNewButton.NativeUI.Style = "Pill"
147 | $this.AddNewButton.NativeUI.ForegroundColor = [Color]::Black
148 | $this.AddNewButton.NativeUI.BackgroundColor = [Color]::Green
149 |
150 | $this.FirstButton.NativeUI.MaxWidth = 7
151 | $this.PreviousButton.NativeUI.MaxWidth = 7
152 | $this.NextButton.NativeUI.MaxWidth = 7
153 | $this.LastButton.NativeUI.MaxWidth = 7
154 | $this.AddNewButton.NativeUI.MaxWidth = 7
155 |
156 | $this.AddNewButton.NativeUI.MaxHeight = 4
157 | $this.AddNewButton.NativeUI.Margin = [Thickness]::new(6, 0, 0, 0)
158 | }
159 | }
160 |
161 | class MaterialCFMenuItem : CFMenuItem {
162 |
163 | MaterialCFMenuItem() {
164 | $this.NativeUI.BackgroundColor = [Color]::Magenta
165 | }
166 | }
167 |
168 | class MaterialCFDropDownMenu : CFDropDownMenu {
169 |
170 | MaterialCFDropDownMenu() {
171 | $this.NativeUI.Style = "Primary"
172 | }
173 | }
174 |
175 | class MaterialCFAutoComplete : CFAutoComplete {
176 |
177 | MaterialCFAutoComplete() {
178 | $this.NativeUI.Style = "Flat"
179 | }
180 |
181 | [void] StyleMenuItem($menuItem) {
182 | $menuItem.BackgroundColor = [Color]::Magenta
183 | }
184 | }
185 |
186 | class MaterialCFCard : CFCard {
187 | }
188 |
189 | class MaterialCFImage : CFImage {
190 | }
191 |
192 | class MaterialCFTextEditor : CFTextEditor {
193 | }
194 |
195 | class MaterialCFExpander : CFExpander {
196 | }
197 |
198 | class MaterialCFInteger : CFInteger {
199 |
200 | MaterialCFInteger() {
201 | $this.NativeUI.Style = "Flat"
202 | }
203 | }
204 |
205 | class MaterialCFDouble : CFDouble {
206 |
207 | MaterialCFDouble() {
208 | $this.NativeUI.Style = "Flat"
209 | }
210 | }
211 |
212 | class MaterialCFComboBoxItem : CFComboBoxItem {
213 |
214 | MaterialCFComboBoxItem() {
215 | $this.NativeUI.BackgroundColor = [Color]::Magenta
216 | }
217 | }
218 |
219 | class MaterialCFComboBox : CFComboBox {
220 |
221 | MaterialCFComboBox() {
222 | $this.NativeUI.Style = "Primary"
223 | }
224 | }
225 |
226 | class MaterialCFFileUpload : CFFileUpload {
227 | }
--------------------------------------------------------------------------------
/UIfied/UIfiedMaterialOouiBase.ps1:
--------------------------------------------------------------------------------
1 | using namespace Ooui
2 |
3 | class MaterialOouiHost : OouiHost {
4 |
5 | MaterialOouiHost() {
6 | [UI]::HeadHtml = '
7 |
8 |
9 |
53 | '
54 | [UI]::BodyFooterHtml = ''
55 | }
56 | }
57 |
58 | class MaterialOouiWindow : OouiWindow {
59 | }
60 |
61 | class MaterialOouiStackPanel : OouiStackPanel {
62 | }
63 |
64 | class MaterialOouiIcon : OouiIcon {
65 | }
66 |
67 | class MaterialOouiLabel : OouiLabel {
68 | }
69 |
70 | class MaterialOouiButton : OouiButton {
71 | }
72 |
73 | class MaterialOouiTextBox : OouiTextBox {
74 |
75 | MaterialOouiTextBox() {
76 | $this.NativeUI.ClassName = "form-control"
77 | }
78 |
79 | }
80 |
81 | class MaterialOouiPassword : OouiPassword {
82 |
83 | MaterialOouiPassword() {
84 | $this.NativeUI.ClassName = "form-control"
85 | }
86 |
87 | }
88 |
89 | class MaterialOouiCheckBox : OouiElement {
90 |
91 | #
92 | #
99 | #
100 |
101 | hidden [Div] $ListNativeUI = [Div]::new()
102 | hidden [Label] $CheckLabelNativeUI = [Label]::new()
103 | hidden [Input] $CheckBoxNativeUI = [Input]::new("CheckBox")
104 | hidden [Span] $SignNativeUI = [span]::new()
105 | hidden [Span] $SpanNativeUI = [span]::new()
106 | hidden [Span] $LabelTextNativeUI = [span]::new()
107 |
108 | MaterialOouiCheckBox() {
109 | $this.ListNativeUI.ClassName = "form-check"
110 | $this.CheckLabelNativeUI.ClassName = "form-check-label"
111 | $this.CheckBoxNativeUI.ClassName = "form-check-input"
112 | $this.SignNativeUI.ClassName = "form-check-sign"
113 | $this.SpanNativeUI.ClassName = "check"
114 |
115 | $this.LabelTextNativeUI.Style.PaddingLeft = "25px"
116 |
117 | $this.ListNativeUI.AppendChild($this.CheckLabelNativeUI)
118 | $this.CheckLabelNativeUI.AppendChild($this.CheckBoxNativeUI)
119 | $this.CheckLabelNativeUI.AppendChild($this.SignNativeUI)
120 | $this.CheckLabelNativeUI.AppendChild($this.LabelTextNativeUI)
121 | $this.SignNativeUI.AppendChild($this.SpanNativeUI)
122 | $this.SetNativeUI($this.ListNativeUI)
123 |
124 | $this.WrapProperty("Caption", "Text", "LabelTextNativeUI")
125 | $this.WrapProperty("IsChecked", "IsChecked", "CheckBoxNativeUI")
126 | $this.AddScriptBlockProperty("Click")
127 | Register-ObjectEvent -InputObject $this.CheckBoxNativeUI -EventName Change -MessageData $this -Action {
128 | $this = $event.MessageData
129 | $this.Control.OnClick()
130 | } | Out-Null
131 | }
132 |
133 | [void] OnClick() {
134 | Invoke-Command -ScriptBlock $this._Click -ArgumentList $this
135 | }
136 |
137 | }
138 |
139 | class MaterialOouiRadioButton : OouiElement {
140 |
141 | #
142 | #
149 | #
150 |
151 | hidden [Div] $ListNativeUI = [Div]::new()
152 | hidden [Label] $CheckLabelNativeUI = [Label]::new()
153 | hidden [Input] $RadioButtonNativeUI = [Input]::new("Radio")
154 | hidden [Span] $SignNativeUI = [span]::new()
155 | hidden [Span] $SpanNativeUI = [span]::new()
156 | hidden [Span] $LabelTextNativeUI = [span]::new()
157 |
158 | MaterialOouiRadioButton() {
159 | $this.ListNativeUI.ClassName = "form-check"
160 | $this.CheckLabelNativeUI.ClassName = "form-check-label"
161 | $this.RadioButtonNativeUI.ClassName = "form-check-input"
162 | $this.SignNativeUI.ClassName = "circle"
163 | $this.SpanNativeUI.ClassName = "check"
164 |
165 | $this.LabelTextNativeUI.Style.PaddingLeft = "25px"
166 |
167 | $this.ListNativeUI.AppendChild($this.CheckLabelNativeUI)
168 | $this.CheckLabelNativeUI.AppendChild($this.RadioButtonNativeUI)
169 | $this.CheckLabelNativeUI.AppendChild($this.SignNativeUI)
170 | $this.CheckLabelNativeUI.AppendChild($this.LabelTextNativeUI)
171 | $this.SignNativeUI.AppendChild($this.SpanNativeUI)
172 | $this.SetNativeUI($this.ListNativeUI)
173 |
174 | $this.WrapProperty("Caption", "Text", "LabelTextNativeUI")
175 | $this.WrapProperty("IsChecked", "IsChecked", "RadioButtonNativeUI")
176 | $this.AddScriptBlockProperty("Click")
177 | Register-ObjectEvent -InputObject $this.RadioButtonNativeUI -EventName Change -MessageData $this -Action {
178 | $this = $event.MessageData
179 | $this.Control.OnClick()
180 | } | Out-Null
181 | }
182 |
183 | [void] OnClick() {
184 | Invoke-Command -ScriptBlock $this._Click -ArgumentList $this
185 | }
186 |
187 | }
188 |
189 | class MaterialOouiRadioGroup : OouiRadioGroup {
190 | }
191 |
192 | class MaterialOouiList : OouiList {
193 | }
194 |
195 | class MaterialOouiListColumn : OouiListColumn {
196 | }
197 |
198 | class MaterialOouiTabItem : OouiTabItem {
199 | }
200 |
201 | class MaterialOouiTabControl : OouiTabControl {
202 |
203 | RefreshStyle() {
204 | $this.List.ClassName = "nav nav-pills nav-pills-primary"
205 | }
206 |
207 | }
208 |
209 | class MaterialOouiModal : OouiModal {
210 | }
211 |
212 | class MaterialOouiTimer : OouiTimer {
213 | }
214 |
215 | class MaterialOouiDatePicker : OouiDatePicker {
216 | }
217 |
218 | class MaterialOouiTimePicker : OouiTimePicker {
219 | }
220 |
221 | class MaterialOouiBrowser : OouiBrowser {
222 |
223 | [void] StyleComponents() {
224 | $this.List.NativeUI.ClassName = "UIList table"
225 |
226 | $this.FirstButton.Icon = [OouiIcon] @{ Kind = "first_page" }
227 | $this.PreviousButton.Icon = [OouiIcon] @{ Kind = "chevron_left" }
228 | $this.NextButton.Icon = [OouiIcon] @{ Kind = "chevron_right" }
229 | $this.LastButton.Icon = [OouiIcon] @{ Kind = "last_page" }
230 | $this.AddNewButton.Icon = [OouiIcon] @{ Kind = "add" }
231 |
232 | $this.FirstButton.NativeUI.ClassName = "btn btn-primary btn-link"
233 | $this.PreviousButton.NativeUI.ClassName = "btn btn-primary btn-link"
234 | $this.NextButton.NativeUI.ClassName = "btn btn-primary btn-link"
235 | $this.LastButton.NativeUI.ClassName = "btn btn-primary btn-link"
236 | $this.AddNewButton.NativeUI.ClassName = "btn btn-fab btn-round btn-lg"
237 |
238 | $this.AddNewButton.NativeUI.Style.BackgroundColor = "lime"
239 | }
240 |
241 | [void] StyleEditionButtons([OouiButton] $editButton, [OouiButton] $deleteButton, [int] $rowIndex) {
242 | $editButton.Icon = [MaterialOouiIcon] @{ Kind = "edit" }
243 | $deleteButton.Icon = [MaterialOouiIcon] @{ Kind = "close" }
244 |
245 | $editButton.NativeUI.ClassName = "btn btn-success btn-link btn-sm"
246 | $deleteButton.NativeUI.ClassName = "btn btn-danger btn-link btn-sm"
247 | $editButton.Parent.NativeUI.ClassName = "td-actions"
248 | }
249 |
250 | }
251 |
252 | class MaterialOouiMenuItem : OouiMenuItem {
253 | }
254 |
255 | class MaterialOouiDropDownMenu : OouiDropDownMenu {
256 | }
257 |
258 | class MaterialOouiAutoComplete : OouiAutoComplete {
259 | }
260 |
261 | class MaterialOouiCard : OouiCard {
262 | }
263 |
264 | class MaterialOouiImage : OouiImage {
265 | }
266 |
267 | class MaterialOouiTextEditor : OouiTextEditor {
268 | }
269 |
270 | class MaterialOouiExpander : OouiElement {
271 | hidden [div] $ExpanderContainerDiv = [div]::new()
272 | hidden [div] $ExpanderHeaderDiv = [div]::new()
273 | hidden [div] $ExpanderButtonDiv = [div]::new()
274 | hidden [OouiStackPanel] $ExpanderBodyDiv = [OouiStackPanel]::new()
275 | hidden [Button] $ExpanderButton = [Button]::new()
276 | hidden [Heading] $Header = [Heading]::new(3)
277 | hidden [Icon] $ExpanderIcon = [Icon]::new()
278 |
279 | MaterialOouiExpander() {
280 | $this.SetNativeUI($this.ExpanderContainerDiv)
281 | $this.ExpanderContainerDiv.AppendChild($this.ExpanderHeaderDiv)
282 | $this.ExpanderContainerDiv.AppendChild($this.ExpanderBodyDiv.NativeUI)
283 | $this.ExpanderHeaderDiv.AppendChild($this.ExpanderButtonDiv)
284 | $this.ExpanderHeaderDiv.AppendChild($this.Header)
285 | $this.ExpanderButtonDiv.AppendChild($this.ExpanderButton)
286 | $this.ExpanderButton.AppendChild($this.ExpanderIcon)
287 |
288 | $this.WrapProperty("Caption", "Text", "Header")
289 | $this.AddNativeUIChild = {
290 | param (
291 | [OouiElement] $element
292 | )
293 | $listItem = [Div]::new()
294 | if ($this.ExpanderBodyDiv.Orientation -eq [Orientation]::Horizontal) {
295 | $listItem.Style.float = "left"
296 | } else {
297 | $listItem.Style.clear = "both"
298 | }
299 | $this.ExpanderBodyDiv.NativeUI.AppendChild($listItem) | Out-Null
300 | $listItem.AppendChild($element.NativeUI) | Out-Null
301 | }
302 | Register-ObjectEvent -InputObject $this.ExpanderButton -EventName Click -MessageData $this -Action {
303 | $this = $event.MessageData
304 | $this.ToogleContent()
305 | } | Out-Null
306 | $this.StyleComponents()
307 | }
308 |
309 | [void] StyleComponents() {
310 | $this.ExpanderButton.ClassName = "btn btn-primary btn-link btn-sm"
311 | $this.ExpanderButton.Style.Padding = "0"
312 | $this.ExpanderIcon.ClassName = "material-icons"
313 | $this.ExpanderIcon.Text = "expand_less"
314 | $this.ExpanderButtonDiv.Style.float = "left"
315 | $this.Header.Style.display = "inline"
316 | $this.ExpanderIcon.Style.FontSize = "2rem"
317 | $this.ExpanderHeaderDiv.Style.BorderBottomStyle = "solid"
318 | $this.ExpanderHeaderDiv.Style.BorderBottomColor = "#ddd"
319 | $this.ExpanderHeaderDiv.Style.BorderBottomWidth = "1px"
320 | }
321 |
322 | [void] ToogleContent() {
323 | $this.ExpanderBodyDiv.Visible = -not $this.ExpanderBodyDiv.Visible
324 | if ($this.ExpanderIcon.Text -eq "expand_more") {
325 | $this.ExpanderIcon.Text = "expand_less"
326 | } else {
327 | $this.ExpanderIcon.Text = "expand_more"
328 | }
329 | }
330 | }
331 |
332 | class MaterialOouiInteger : OouiInteger {
333 |
334 | MaterialOouiInteger() {
335 | $this.NativeUI.ClassName = "form-control"
336 | }
337 | }
338 |
339 | class MaterialOouiDouble : OouiDouble {
340 |
341 | MaterialOouiDouble() {
342 | $this.NativeUI.ClassName = "form-control"
343 | }
344 | }
345 |
346 | class MaterialOouiComboBoxItem : OouiComboBoxItem {
347 | }
348 |
349 | class MaterialOouiCombobox : OouiCombobox {
350 | }
351 |
352 | class MaterialOouiFileUpload : OouiFileUpload {
353 | }
--------------------------------------------------------------------------------
/UIfied/UIfiedMaterialWPFBase.ps1:
--------------------------------------------------------------------------------
1 | using namespace System.Collections.Generic
2 | using namespace System.Windows
3 | using namespace System.Windows.Controls
4 | using namespace MaterialDesignThemes.Wpf
5 |
6 | class MaterialWPFHost : WPFHost {
7 | }
8 |
9 | class MaterialWPFWindow : WPFWindow {
10 |
11 | [void] StyleApplication() {
12 | $uris =
13 | "/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Light.xaml",
14 | "/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.Defaults.xaml",
15 | "/MaterialDesignColors;component/Themes/Recommended/Primary/MaterialDesignColor.DeepPurple.xaml",
16 | "/MaterialDesignColors;component/Themes/Recommended/Accent/MaterialDesignColor.Lime.xaml"
17 |
18 | $uris | ForEach-Object {
19 | $resourceDictionary = [System.Windows.ResourceDictionary] [System.Windows.Application]::LoadComponent([Uri]::new($_, [System.UriKind]::Relative))
20 | $this.Application.Resources.MergedDictionaries.Add($resourceDictionary)
21 | }
22 | }
23 |
24 | [void] StyleComponents() {
25 | $this.windowNativeUI.FontFamily = "MaterialDesignFont"
26 | $this.windowNativeUI.SetResourceReference([Control]::BackgroundProperty, "MaterialDesignPaper")
27 | }
28 | }
29 |
30 | class MaterialWPFStackPanel : WPFStackPanel {
31 | }
32 |
33 | class MaterialWPFIcon : WPFElement {
34 | hidden [String] $KindName
35 | hidden $TextInfo
36 | static $IconTranslation = [PSCustomObject] @{
37 | document = "FileDocument"
38 | }
39 |
40 | MaterialWPFIcon() {
41 | $this.TextInfo = ([System.Globalization.CultureInfo]::new("en-US",$false)).TextInfo
42 | $this.NativeUI = [MaterialDesignThemes.Wpf.PackIcon]::new()
43 | Add-Member -InputObject $this -Name Kind -MemberType ScriptProperty -Value {
44 | $this.KindName
45 | } -SecondValue {
46 | $this.KindName = $args[0]
47 | if ([MaterialWPFIcon]::IconTranslation."$($this.KindName)" -ne $null) {
48 | $this.NativeUI.Kind = [MaterialWPFIcon]::IconTranslation."$($this.KindName)"
49 | } else {
50 | $this.NativeUI.Kind = $this.TextInfo.ToTitleCase($this.KindName).Replace("_", [String]::Empty)
51 | }
52 | }
53 | }
54 | }
55 |
56 | class MaterialWPFLabel : WPFLabel {}
57 |
58 | class MaterialWPFButton : WPFElement {
59 | hidden [stackpanel] $StackPanel = [StackPanel]::new()
60 | hidden [MaterialWPFIcon] $CurrentIcon = $null
61 | hidden [String] $CaptionText = ""
62 | [bool] $RightIcon = $false
63 |
64 | MaterialWPFButton() {
65 | $this.SetNativeUI([Button]::new())
66 | $this.NativeUI.SetResourceReference([Control]::StyleProperty, "MaterialDesignRaisedButton")
67 | $this.StackPanel.Orientation = [Orientation]::Horizontal
68 | $this.NativeUI.Content = $this.StackPanel
69 | Add-Member -InputObject $this -Name Caption -MemberType ScriptProperty -Value {
70 | $this.CaptionText
71 | } -SecondValue {
72 | $this.CaptionText = $args[0]
73 | $this.RefreshCaption()
74 | }
75 | Add-Member -InputObject $this -Name Icon -MemberType ScriptProperty -Value {
76 | $this.CurrentIcon
77 | } -SecondValue {
78 | $this.CurrentIcon = $args[0]
79 | $this.RefreshCaption()
80 | }
81 | $this.AddScriptBlockProperty("Action")
82 | $this.NativeUI.Add_Click({ $this.Control.OnAction() })
83 | }
84 |
85 | [void] RefreshCaption() {
86 | $this.StackPanel.Children.Clear()
87 |
88 | $label = [TextBlock]::new()
89 | $label.Text = $this.CaptionText
90 |
91 | if ($this.RightIcon) {
92 | $this.StackPanel.AddChild($label)
93 | if ($this.CurrentIcon -ne $null) {
94 | $this.StackPanel.AddChild($this.CurrentIcon.NativeUI)
95 | }
96 | } else {
97 | if ($this.CurrentIcon -ne $null) {
98 | $this.StackPanel.AddChild($this.CurrentIcon.NativeUI)
99 | }
100 | $this.StackPanel.AddChild($label)
101 | }
102 | }
103 |
104 | [void] OnAction() {
105 | $this.InvokeTrappableCommand($this._Action, $this)
106 | }
107 |
108 | }
109 |
110 | class MaterialWPFTextBox : WPFTextBox {
111 | }
112 |
113 | class MaterialWPFPassword : WPFPassword {
114 | }
115 |
116 | class MaterialWPFCheckBox : WPFCheckBox {
117 |
118 | MaterialWPFCheckBox() {
119 | $this.NativeUI.SetResourceReference([Control]::StyleProperty, "MaterialDesignCheckBox")
120 | }
121 | }
122 |
123 | class MaterialWPFRadioButton : WPFRadioButton {
124 |
125 | MaterialWPFCheckBox() {
126 | $this.NativeUI.SetResourceReference([Control]::StyleProperty, "MaterialDesignRadioButton")
127 | }
128 | }
129 |
130 | class MaterialWPFRadioGroup : WPFRadioGroup {
131 | }
132 |
133 | class MaterialWPFList : WPFList {
134 | }
135 |
136 | class MaterialWPFListColumn : WPFListColumn {
137 | }
138 |
139 | class MaterialWPFTabItem : MaterialWPFStackPanel {
140 | [MaterialWPFRadioButton] $HeaderRadioButton = ([MaterialWPFRadioButton] @{ Caption = "" })
141 | hidden [String] $CaptionText = ""
142 |
143 | MaterialWPFTabItem() {
144 | Add-Member -InputObject $this.HeaderRadioButton -Name Tab -Value $this -MemberType NoteProperty
145 |
146 | #$this.WrapProperty("Caption", "Caption", "HeaderRadioButton")
147 | Add-Member -InputObject $this -Name Caption -MemberType ScriptProperty -Value {
148 | $this.CaptionText
149 | } -SecondValue {
150 | $this.CaptionText = $args[0]
151 | $this.HeaderRadioButton.Caption = $args[0].ToUpperInvariant()
152 | }
153 |
154 | $this.HeaderRadioButton.NativeUI.SetResourceReference([Control]::StyleProperty, "MaterialDesignTabRadioButton")
155 | $this.Visible = $false
156 | $this.HeaderRadioButton.Click = {
157 | $this.Control.Tab.Parent.HideTabs()
158 | $this.Control.Tab.Visible = $this.Control.IsChecked
159 | }
160 | }
161 | }
162 |
163 | class MaterialWPFTabControl : MaterialWPFStackPanel {
164 | hidden [MaterialWPFStackPanel] $HeadersStackPanel = ([MaterialWPFStackPanel] @{ Orientation = [Orientation]::Horizontal })
165 | hidden [MaterialWPFStackPanel] $TabsStackPanel = ([MaterialWPFStackPanel] @{ Orientation = [Orientation]::Horizontal })
166 | hidden $TabItems = [List[MaterialWPFTabItem]]::new()
167 |
168 | MaterialWPFTabControl() {
169 | $this.Orientation = [Orientation]::Vertical
170 | $this.AddChild($this.HeadersStackPanel)
171 | $this.AddChild($this.TabsStackPanel)
172 | $this.AddNativeUIChild = {
173 | param (
174 | [MaterialWPFTabItem] $element
175 | )
176 | $this.TabItems.Add($element)
177 | $this.HeadersStackPanel.AddChild($element.HeaderRadioButton) | Out-Null
178 | $this.TabsStackPanel.NativeUI.AddChild($element.NativeUI) | Out-Null
179 | }
180 | $this.RemoveNativeUIChild = {
181 | param (
182 | [MaterialWPFTabItem] $element
183 | )
184 | $this.TabItems.Remove($element)
185 | $this.HeadersStackPanel.RemoveChild($element.HeaderRadioButton) | Out-Null
186 | $this.TabsStackPanel.NativeUI.Children.Remove($element.NativeUI) | Out-Null
187 | }
188 | }
189 |
190 | [void] HideTabs() {
191 | $this.TabItems | ForEach-Object {
192 | $_.Visible = $false
193 | }
194 | }
195 |
196 | }
197 |
198 | class MaterialWPFModal : WPFModal {
199 | }
200 |
201 | class MaterialWPFTimer : WPFTimer {
202 | }
203 |
204 | class MaterialWPFDatePicker : WPFElement {
205 |
206 | MaterialWPFDatePicker() {
207 | $datePicker = [DatePicker]::new()
208 | $datePicker.Width = 100
209 | $datePicker.SetResourceReference([Control]::StyleProperty, "MaterialDesignDatePicker")
210 | $this.SetNativeUI($datePicker)
211 |
212 | $this.AddScriptBlockProperty("Change")
213 | $this.NativeUI.Add_SelectedDateChanged({ $this.Control.OnChange() })
214 | $this.AddScriptBlockProperty("LostFocus")
215 | $this.NativeUI.Add_LostFocus({ $this.Control.OnLostFocus() })
216 |
217 | $this.WrapProperty("Value", "SelectedDate")
218 | }
219 |
220 | [void] OnChange() {
221 | $this.InvokeTrappableCommand($this._Change, $this)
222 | }
223 |
224 | [void] OnLostFocus() {
225 | $this.InvokeTrappableCommand($this._LostFocus, $this)
226 | }
227 | }
228 |
229 | class MaterialWPFTimePicker : WPFElement {
230 |
231 | MaterialWPFTimePicker() {
232 | $timePicker = [TimePicker]::new()
233 | $timePicker.Width = 100
234 | $timePicker.SetResourceReference([Control]::StyleProperty, "MaterialDesignTimePicker")
235 | $timePicker.Is24Hours = $true
236 | $this.SetNativeUI($timePicker)
237 |
238 | $this.AddScriptBlockProperty("Change")
239 | $this.NativeUI.Add_SelectedTimeChanged({ $this.Control.OnChange() })
240 | $this.AddScriptBlockProperty("LostFocus")
241 | $this.NativeUI.Add_LostFocus({ $this.Control.OnLostFocus() })
242 |
243 | $this.WrapProperty("Value", "SelectedTime")
244 | }
245 |
246 | [void] OnChange() {
247 | $this.InvokeTrappableCommand($this._Change, $this)
248 | }
249 |
250 | [void] OnLostFocus() {
251 | $this.InvokeTrappableCommand($this._LostFocus, $this)
252 | }
253 | }
254 |
255 | class MaterialWPFBrowser : WPFBrowser {
256 |
257 | [void] StyleComponents() {
258 | $this.StyleButton($this.FirstButton, "FirstPage", "MaterialDesignIconButton")
259 | $this.StyleButton($this.PreviousButton, "ChevronLeft", "MaterialDesignIconButton")
260 | $this.StyleButton($this.NextButton, "ChevronRight", "MaterialDesignIconButton")
261 | $this.StyleButton($this.LastButton, "LastPage", "MaterialDesignIconButton")
262 |
263 | $this.StyleButton($this.AddNewButton, "Add", "MaterialDesignFloatingActionAccentButton")
264 |
265 | $this.FirstButton.Parent.NativeUI.Margin = "0 -10 0 10"
266 | $this.AddNewButton.NativeUI.Margin = "100 10 10 10"
267 | }
268 |
269 | [void] StyleButton($button, $iconKind, $styleName) {
270 | $button.NativeUI.Content = New-Object PackIcon -Property @{ Kind = $iconKind }
271 | $button.NativeUI.Margin = 0
272 | $button.NativeUI.SetResourceReference([Control]::StyleProperty, $styleName)
273 | }
274 |
275 | [void] StyleEditionButtons([WPFButton] $editButton, [WPFButton] $deleteButton, [int] $rowIndex) {
276 | $editButton.Parent.NativeUI.Background = $this.GetRowBackground($rowIndex)
277 |
278 | $this.StyleButton($editButton, "ModeEdit", "MaterialDesignIconMiniButton")
279 | $this.StyleButton($deleteButton, "WindowClose", "MaterialDesignIconMiniButton")
280 |
281 | $editButton.NativeUI.Background = [System.Windows.Media.Brushes]::Transparent
282 | $deleteButton.NativeUI.Background = [System.Windows.Media.Brushes]::Transparent
283 |
284 | $editButton.NativeUI.Foreground = [System.Windows.Media.Brushes]::Green
285 | $deleteButton.NativeUI.Foreground = [System.Windows.Media.Brushes]::Red
286 |
287 | $editButton.NativeUI.BorderThickness = 0
288 | $deleteButton.NativeUI.BorderThickness = 0
289 | }
290 |
291 | }
292 |
293 | class MaterialWPFMenuItem : WPFMenuItem {
294 | }
295 |
296 | class MaterialWPFDropDownMenu : MaterialWPFButton {
297 |
298 | MaterialWPFDropDownMenu() {
299 | $this.RightIcon = $true
300 | $this.Icon = [MaterialWPFIcon] @{ Kind = "chevron_down" }
301 |
302 | $this.NativeUI.ContextMenu = [ContextMenu]::new()
303 | $this.AddNativeUIChild = {
304 | param (
305 | [WPFElement] $element
306 | )
307 | $this.NativeUI.ContextMenu.Items.Add($element.NativeUI)
308 | }
309 | $this.RemoveNativeUIChild = {
310 | param (
311 | [WPFElement] $element
312 | )
313 | $this.NativeUI.ContextMenu.Items.Remove($element.NativeUI)
314 | }
315 |
316 | $this.Action = {
317 | param($this)
318 | $this.NativeUI.ContextMenu.IsOpen = -not $this.NativeUI.ContextMenu.IsOpen
319 | }
320 | }
321 |
322 | }
323 |
324 | class MaterialWPFAutoComplete : WPFAutoComplete {
325 | }
326 |
327 | class MaterialWPFCard : WPFCard {
328 | hidden $CurrentIcon = [MaterialWPFIcon]::new()
329 |
330 | [void] StyleComponents() {
331 | ([WPFCard] $this).StyleComponents()
332 | $this.NativeUI.SetResourceReference([Control]::StyleProperty, "MaterialDesignCardGroupBox")
333 | $this.HeaderTextBlock.Foreground = [System.Windows.Media.Brushes]::White
334 | $this.CurrentIcon.NativeUI.Foreground = [System.Windows.Media.Brushes]::White
335 | $this.HeaderTextBlock.SetResourceReference([Control]::StyleProperty, "MaterialDesignSubHeadingTextBlock")
336 | }
337 | }
338 |
339 | class MaterialWPFImage : WPFImage {
340 | }
341 |
342 | class MaterialWPFTextEditor : WPFTextEditor {
343 | }
344 |
345 | class MaterialWPFExpander : WPFExpander {
346 | }
347 |
348 | class MaterialWPFInteger : WPFInteger {
349 | }
350 |
351 | class MaterialWPFDouble : WPFDouble {
352 | }
353 |
354 | class MaterialWPFComboBoxItem : WPFComboBoxItem {
355 | }
356 |
357 | class MaterialWPFComboBox : WPFComboBox {
358 | }
359 |
360 | class MaterialWPFFileUpload : WPFFileUpload {
361 | }
--------------------------------------------------------------------------------
/UIfied/UIfiedOouiBase.ps1:
--------------------------------------------------------------------------------
1 | using namespace System.Collections.Generic
2 | using namespace Ooui
3 |
4 | #region Ooui missing elements
5 |
6 | class Icon : Element {
7 |
8 | Icon() : base("i") {
9 | }
10 | }
11 |
12 | class Table : Element {
13 |
14 | Table() : base("table") {
15 | }
16 | }
17 |
18 | class TableHeader : Element {
19 |
20 | TableHeader() : base("thead") {
21 | }
22 | }
23 |
24 | class TableBody : Element {
25 |
26 | TableBody() : base("tbody") {
27 | }
28 | }
29 |
30 | class TableRow : Element {
31 |
32 | TableRow() : base("tr") {
33 | }
34 | }
35 |
36 | class TableHeaderCell : Element {
37 |
38 | TableHeaderCell() : base("th") {
39 | }
40 | }
41 |
42 | class TableDataCell : Element {
43 |
44 | TableDataCell() : base("td") {
45 | }
46 | }
47 |
48 | #endregion
49 |
50 | class OouiElement : UIElement {
51 |
52 | OouiElement() {
53 | $this.WrapNegatedProperty("Enable", "IsDisabled")
54 | $this.WrapNegatedProperty("Visible", "IsHidden")
55 | $this.AddNativeUIChild = {
56 | param (
57 | [OouiElement] $element
58 | )
59 | $this.NativeUI.AppendChild($element.NativeUI) | Out-Null
60 | }
61 | $this.RemoveNativeUIChild = {
62 | param (
63 | [OouiElement] $element
64 | )
65 | $this.NativeUI.RemoveChild($element.NativeUI) | Out-Null
66 | }
67 | }
68 | }
69 |
70 | class OouiHost : UIHost {
71 | $Shared = $false
72 | $Port = 8185
73 | $Host = [UI]::Host
74 | [ScriptBlock] $CreateElement
75 |
76 | OouiHost() {
77 | # Style documentation in https://getbootstrap.com/docs/5.0
78 | [UI]::HeadHtml = '
79 |
80 |
81 |
106 | '
107 | [UI]::BodyFooterHtml = '
108 |
109 | '
110 | }
111 |
112 | [void] ShowFrame([ScriptBlock] $frameScriptBlock) {
113 | #$Global:SyncHash = [HashTable]::Synchronized(@{
114 | # Window = $null
115 | # Errors = @()
116 | #})
117 |
118 | $this.CreateElement = $frameScriptBlock
119 | if ($this.Shared) {
120 | $this.ShowSharedFrame()
121 | } else {
122 | $this.ShowNotSharedFrame()
123 | }
124 | }
125 |
126 | [void] ShowSharedFrame() {
127 | $frame = Invoke-Command -ScriptBlock $this.CreateElement
128 | [UI]::Port = $this.Port
129 | [UI]::Publish("/Form", $frame.NativeUI)
130 | }
131 |
132 | [void] ShowNotSharedFrame() {
133 | $notSharedForm = [NotSharedForm]::new($this.Host, $this.Port, "/Form")
134 | $notSharedForm.CreateElement = $this.CreateElement
135 | $notSharedForm.Publish()
136 | }
137 | }
138 |
139 | class NotSharedForm : Div {
140 | [Anchor] $Anchor
141 | [ScriptBlock] $CreateElement
142 | [string] $Host
143 | [int] $Port
144 | [string] $Path
145 |
146 | NotSharedForm([string]$host, [int]$port, [string]$path) {
147 | $this.Host = $host
148 | $this.Port = $port
149 | $this.Path = $path
150 | }
151 |
152 | Publish() {
153 | $hostWrapper = [OouiWrapper.OouiWrapper]::new($this.Port, $this.Path)
154 | $hostWrapper.Host = $this.Host
155 | $hostWrapper.Publish()
156 | $hostWrapper.PublishFileUpload($env:UploadPath, "/files/upload")
157 | Add-Member -InputObject $hostWrapper -MemberType NoteProperty -Name sb -Value $this.CreateElement | Out-Null
158 | Register-ObjectEvent -InputObject $hostWrapper -EventName OnPublish -MessageData $hostWrapper -Action {
159 | param ($hostWrapper)
160 | $window = Invoke-Command -ScriptBlock $event.MessageData.sb
161 | $event.MessageData.Frame = $window.NativeUI
162 | } | Out-Null
163 | }
164 | }
165 |
166 | class OouiWindow : WindowBase {
167 |
168 | OouiWindow() {
169 | $this.SetNativeUI([Div]::new())
170 | $this.WrapProperty("Caption", "Title")
171 | $this.AddScriptBlockProperty("Loaded")
172 | $this.AddNativeUIChild = {
173 | param (
174 | [OouiElement] $element
175 | )
176 | $this.NativeUI.AppendChild($element.NativeUI)
177 | }
178 | }
179 |
180 | [void] ShowDialog() {
181 | }
182 |
183 | [void] OnLoaded() {
184 | Invoke-Command -ScriptBlock $this._Loaded -ArgumentList $this
185 | }
186 | }
187 |
188 | class OouiStackPanel : OouiElement {
189 | #Divs https://jsfiddle.net/rwe8hp6f/
190 |
191 | OouiStackPanel() {
192 | $this.SetNativeUI([Div]::new())
193 | $this.AddProperty("Orientation")
194 | $this.AddNativeUIChild = {
195 | param (
196 | [OouiElement] $element
197 | )
198 | $listItem = [Div]::new()
199 | if ($this._Orientation -eq [Orientation]::Horizontal) {
200 | $listItem.Style.float = "left"
201 | } else {
202 | $listItem.Style.clear = "both"
203 | #$listItem.Style.Display = ""
204 | }
205 | $this.NativeUI.AppendChild($listItem) | Out-Null
206 | $listItem.AppendChild($element.NativeUI) | Out-Null
207 | }
208 | }
209 | }
210 |
211 | class OouiIcon : OouiElement {
212 | [String] $KindName = ""
213 | static $IconTranslation = [PSCustomObject] @{
214 | document = "description"
215 | }
216 |
217 | OouiIcon() {
218 | $nativeUI = [Icon]::new()
219 | $nativeUI.ClassName = "material-icons"
220 | $this.SetNativeUI($nativeUI)
221 | Add-Member -InputObject $this -Name Kind -MemberType ScriptProperty -Value {
222 | $this.KindName
223 | } -SecondValue {
224 | $this.KindName = $args[0]
225 | if ([OouiIcon]::IconTranslation."$($this.KindName)" -ne $null) {
226 | $this.NativeUI.Text = [OouiIcon]::IconTranslation."$($this.KindName)"
227 | } else {
228 | $this.NativeUI.Text = $this.KindName
229 | }
230 | }
231 | }
232 |
233 | }
234 |
235 | class OouiLabel : OouiElement {
236 |
237 | OouiLabel() {
238 | $this.SetNativeUI([Span]::new())
239 | $this.WrapProperty("Caption", "Text")
240 | }
241 | }
242 |
243 | class OouiButton : OouiElement {
244 | hidden [OOuiIcon] $CurrentIcon = $null
245 | hidden [span] $CurrentSpan = $null
246 | hidden [String] $CaptionText = ""
247 |
248 | OouiButton() {
249 | $nativeUI = [Button]::new("")
250 | $nativeUI.ClassName = "btn btn-primary"
251 | $this.SetNativeUI($nativeUI)
252 | Add-Member -InputObject $this -Name Caption -MemberType ScriptProperty -Value {
253 | $this.CaptionText
254 | } -SecondValue {
255 | $this.RemoveChildren()
256 | $this.CaptionText = $args[0]
257 | $this.RefreshCaption()
258 | }
259 | Add-Member -InputObject $this -Name Icon -MemberType ScriptProperty -Value {
260 | $this.CurrentIcon
261 | } -SecondValue {
262 | $this.RemoveChildren()
263 | $this.CurrentIcon = $args[0]
264 | $this.RefreshCaption()
265 | }
266 | $this.AddScriptBlockProperty("Action")
267 | Register-ObjectEvent -InputObject $this.NativeUI -EventName Click -MessageData $this -Action {
268 | $this = $event.MessageData
269 | $this.Control.OnAction()
270 | } | Out-Null
271 | }
272 |
273 | [void] RemoveChildren() {
274 | if ($this.CurrentSpan -ne $null) {
275 | $this.NativeUI.RemoveChild($this.CurrentSpan)
276 | }
277 | if ($this.CurrentIcon -ne $null) {
278 | $this.NativeUI.RemoveChild($this.CurrentIcon.NativeUI)
279 | }
280 | }
281 |
282 | [void] RefreshCaption() {
283 | if ($this.CurrentIcon -ne $null) {
284 | $this.NativeUI.AppendChild($this.CurrentIcon.NativeUI)
285 | }
286 | if ($this.CaptionText -ne "") {
287 | $this.CurrentSpan = [Span]::new()
288 | $this.CurrentSpan.Text = $this.CaptionText
289 | $this.NativeUI.AppendChild($this.CurrentSpan)
290 | }
291 | }
292 |
293 | [void] OnAction() {
294 | Invoke-Command -ScriptBlock $this._Action -ArgumentList $this
295 | }
296 | }
297 |
298 | class OouiTextBox : OouiElement {
299 | [String] $Pattern = ""
300 | [String] $DefaultText = ""
301 |
302 | OouiTextBox() {
303 | $this.SetNativeUIControl()
304 | $this.WrapProperty("Text", "Value")
305 | $this.AddScriptBlockProperty("Change")
306 | Register-ObjectEvent -InputObject $this.NativeUI -EventName Change -MessageData $this -Action {
307 | $this = $event.MessageData
308 | if ($this.Control.Pattern -ne "") {
309 | $regex = [Regex]::new($this.Control.Pattern)
310 | if (-not $regex.IsMatch($this.Control.Text)) {
311 | $this.Control.Text = $this.Control.DefaultText
312 | }
313 | }
314 | $this.Control.OnChange()
315 | } | Out-Null
316 | Add-Member -InputObject $this -Name TextAlignment -MemberType ScriptProperty -Value {
317 | if ($this.NativeUI.Style.TextAlign -eq "left") {
318 | [TextAlignment]::Left
319 | } else {
320 | [TextAlignment]::Right
321 | }
322 | } -SecondValue {
323 | if ($args[0] -eq "Left") {
324 | $this.NativeUI.Style.TextAlign = "left"
325 | } else {
326 | $this.NativeUI.Style.TextAlign = "right"
327 | }
328 |
329 | }
330 | }
331 |
332 | [void] SetNativeUIControl() {
333 | $this.SetNativeUI([TextInput]::new())
334 | }
335 |
336 | [void] OnChange() {
337 | Invoke-Command -ScriptBlock $this._Change -ArgumentList $this
338 | }
339 | }
340 |
341 | class OouiPassword : OouiTextBox {
342 |
343 | [void] SetNativeUIControl() {
344 | $this.SetNativeUI([Input]::new("password"))
345 | }
346 |
347 | }
348 |
349 | class OouiCheckBox : OouiElement {
350 | hidden [Div] $ListNativeUI
351 | hidden [Span] $LabelNativeUI
352 | hidden [Input] $CheckBoxNativeUI
353 |
354 | OouiCheckBox() {
355 | $this.ListNativeUI = [Div]::new()
356 | $this.LabelNativeUI = [Span]::new()
357 | $this.CheckBoxNativeUI = [Input]::new("CheckBox")
358 | $this.ListNativeUI.AppendChild($this.CheckBoxNativeUI)
359 | $this.ListNativeUI.AppendChild($this.LabelNativeUI)
360 | $this.SetNativeUI($this.ListNativeUI)
361 | $this.WrapProperty("Caption", "Text", "LabelNativeUI")
362 | $this.WrapProperty("IsChecked", "IsChecked", "CheckBoxNativeUI")
363 | $this.AddScriptBlockProperty("Click")
364 | Register-ObjectEvent -InputObject $this.CheckBoxNativeUI -EventName Change -MessageData $this -Action {
365 | $this = $event.MessageData
366 | $this.Control.OnClick()
367 | } | Out-Null
368 | }
369 |
370 | [void] OnClick() {
371 | Invoke-Command -ScriptBlock $this._Click -ArgumentList $this
372 | }
373 |
374 | }
375 |
376 | class OouiRadioButton : OouiElement {
377 | hidden [Div] $ListNativeUI
378 | hidden [Span] $LabelNativeUI
379 | hidden [Input] $RadioButtonNativeUI
380 |
381 | OouiRadioButton() {
382 | $this.ListNativeUI = [Div]::new()
383 | $this.LabelNativeUI = [Span]::new()
384 | $this.RadioButtonNativeUI = [Input]::new("Radio")
385 | $this.ListNativeUI.AppendChild($this.RadioButtonNativeUI)
386 | $this.ListNativeUI.AppendChild($this.LabelNativeUI)
387 | $this.SetNativeUI($this.ListNativeUI)
388 | $this.WrapProperty("Caption", "Text", "LabelNativeUI")
389 | $this.WrapProperty("IsChecked", "IsChecked", "RadioButtonNativeUI")
390 | $this.AddScriptBlockProperty("Click")
391 | Register-ObjectEvent -InputObject $this.RadioButtonNativeUI -EventName Change -MessageData $this -Action {
392 | $this = $event.MessageData
393 | $this.Control.OnClick()
394 | } | Out-Null
395 | }
396 |
397 | [void] OnClick() {
398 | Invoke-Command -ScriptBlock $this._Click -ArgumentList $this
399 | }
400 |
401 | }
402 |
403 | class OouiRadioGroup : OouiElement {
404 | hidden [String] $ChildName = ""
405 |
406 | OouiRadioGroup() {
407 | $this.SetNativeUI([Div]::new())
408 | $this.AddNativeUIChild = {
409 | param (
410 | [OouiElement] $element
411 | )
412 | if ($this.Control.ChildName -eq "") {
413 | if ($this.Control.Name -ne "") {
414 | $this.Control.ChildName = $this.Control.Name
415 | } else {
416 | $this.Control.ChildName = "A" + [Guid]::NewGuid().ToString()
417 | }
418 | }
419 | $element.RadioButtonNativeUI.Name = $this.Control.ChildName
420 | $this.NativeUI.AppendChild($element.NativeUI) | Out-Null
421 | }
422 | }
423 | }
424 |
425 | class OouiList : OouiElement {
426 | [List[ListItem]] $Items = [List[ListItem]]::new()
427 | [List[OouiListColumn]] $Columns = [List[OouiListColumn]]::new()
428 |
429 | hidden [Table] $Table = [Table]::new()
430 | hidden [TableHeader] $TableHeader = [TableHeader]::new()
431 | hidden [TableRow] $HeaderRow = [TableRow]::new()
432 | hidden [List[TableHeaderCell]] $HeaderCells = [List[TableHeaderCell]]::new()
433 | hidden [TableBody] $TableBody = [TableBody]::new()
434 | hidden [List[TableRow]] $BodyRows = [List[TableRow]]::new()
435 |
436 | OouiList() {
437 | $this.SetNativeUI($this.Table)
438 | $this.NativeUI.ClassName = "UIList"
439 | $this.Table.AppendChild($this.TableHeader)
440 | $this.TableHeader.AppendChild($this.HeaderRow)
441 | $this.Table.AppendChild($this.TableBody)
442 | }
443 |
444 | [void] AddColumn([OouiListColumn] $listColumn) {
445 | $this.Columns.Add($listColumn)
446 | $cell = [TableHeaderCell]::new()
447 | $cell.Text = $listColumn.Title
448 | $this.HeaderRow.AppendChild($cell)
449 | $this.HeaderCells.Add($cell)
450 | }
451 |
452 | [void] AddItem([ListItem] $listItem) {
453 | $this.Items.Add($listItem)
454 | $row = [TableRow]::new()
455 | $this.BodyRows.Add($row)
456 | $listItem.Children | ForEach-Object {
457 | $cell = [TableDataCell]::new()
458 | Add-Member -InputObject $_.NativeUI -Name Form -MemberType NoteProperty -Value $this.Form
459 | Add-Member -InputObject $_.NativeUI -Name Parent -MemberType NoteProperty -Value $this
460 | $cell.AppendChild($_.NativeUI)
461 | $row.AppendChild($cell)
462 | }
463 | $this.TableBody.AppendChild($row)
464 | }
465 |
466 | [void] StyleComponents() {
467 | }
468 |
469 | [void] StyleCell($cell) {
470 | #$cell.NativeUI.Style.LineHeight = $this.LineHeight
471 | }
472 |
473 | [void] RemoveItem([ListItem] $listItem) {
474 | $itemIndex = $this.Items.IndexOf($listItem)
475 | $row = $this.BodyRows.Item($itemIndex)
476 | $this.BodyRows.Remove($row)
477 | $this.TableBody.RemoveChild($row)
478 | $this.Items.Remove($listItem)
479 | }
480 |
481 | [void] Clear() {
482 | $this.Items.ToArray() | ForEach-Object {
483 | $this.RemoveItem($_)
484 | }
485 | }
486 |
487 | [TableDataCell] GetCell([int] $RowIndex, [int] $ColumnIndex) {
488 | $row = $this.BodyRows.Item($RowIndex)
489 | $cell = $row.Children.Item($ColumnIndex)
490 | return $cell
491 | }
492 | }
493 |
494 | class OouiListColumn {
495 | [String] $Name
496 | [String] $Title
497 | }
498 |
499 | class OouiTabItem : OouiStackPanel {
500 | [String] $Caption = ""
501 | }
502 |
503 | class OouiTabControl : OouiStackPanel {
504 | [Ooui.List] $List = [Ooui.List]::new()
505 |
506 | OouiTabControl() {
507 | $this.NativeUI.AppendChild($this.List)
508 | $this.AddNativeUIChild = {
509 | param (
510 | [OouiElement] $element
511 | )
512 | $item = [Ooui.ListItem]::new()
513 | $item.ClassName = "nav-item"
514 | $anchor = [Ooui.Anchor]::new()
515 | $anchor.ClassName = "nav-link"
516 | $anchor.Text = $element.Caption
517 | Register-ObjectEvent -InputObject $anchor -EventName Click -MessageData @($this, $anchor) -Action {
518 | $event.MessageData
519 | $Control = $event.MessageData[0]
520 | $anchor = $event.MessageData[1]
521 | $Control.SelectTab($anchor.Text)
522 | } | Out-Null
523 | $item.AppendChild($anchor) | Out-Null
524 | $this.List.AppendChild($item) | Out-Null
525 | $this.NativeUI.AppendChild($element.NativeUI) | Out-Null
526 |
527 | $firstTab = $this.GetTabs() | Select-Object -First 1
528 | $this.SelectTab($firstTab.Caption)
529 | }
530 | $this.RefreshStyle()
531 | }
532 |
533 | RefreshStyle() {
534 | $this.List.ClassName = "nav nav-pills"
535 | }
536 |
537 | [OOuiTabItem[]] GetTabs() {
538 | return $this.Children
539 | }
540 |
541 | [void] SelectTab([String] $tabCaption) {
542 | $this.GetTabs() | ForEach-Object {
543 | if ($_.Caption -eq $tabCaption) {
544 | $_.Visible = $true
545 | } else {
546 | $_.Visible = $false
547 | }
548 | }
549 | $this.List.Children | ForEach-Object {
550 | $anchor = $_.FirstChild
551 | if ($anchor.Text -eq $tabCaption) {
552 | $_.ClassName = "nav-item active"
553 | $anchor.ClassName = "nav-link active"
554 | } else {
555 | $_.ClassName = "nav-item"
556 | $anchor.ClassName = "nav-link"
557 | }
558 | }
559 | }
560 |
561 | }
562 |
563 | class OouiModal : OouiElement {
564 | [Div] $DialogDiv = [Div]::new()
565 | [Div] $DocumentDiv = [Div]::new()
566 | [Div] $ContentDiv = [Div]::new()
567 | [Div] $HeaderDiv = [Div]::new()
568 | [Heading] $TitleHeading = [Heading]::new(5)
569 | [Div] $BodyDiv = [Div]::new()
570 |
571 | OouiModal() {
572 | $this.DialogDiv.ClassName = "modal"
573 | $this.DialogDiv.Style.display = "none"
574 | $this.DialogDiv.SetAttribute("role", "dialog")
575 |
576 | $this.DocumentDiv.ClassName = "modal-dialog"
577 | $this.DocumentDiv.SetAttribute("role", "document")
578 | $this.DialogDiv.AppendChild($this.DocumentDiv)
579 |
580 | $this.ContentDiv.ClassName = "modal-content"
581 | $this.DocumentDiv.AppendChild($this.ContentDiv)
582 |
583 | $this.HeaderDiv.ClassName = "modal-header"
584 | $this.ContentDiv.AppendChild($this.HeaderDiv)
585 |
586 | $this.TitleHeading.ClassName = "modal-title"
587 | $this.HeaderDiv.AppendChild($this.TitleHeading)
588 |
589 | $this.BodyDiv.ClassName = "modal-body"
590 | $this.ContentDiv.AppendChild($this.BodyDiv)
591 |
592 | $this.SetNativeUI($this.DialogDiv)
593 | $this.AddNativeUIChild = {
594 | param (
595 | [OouiElement] $element
596 | )
597 | $this.BodyDiv.AppendChild($element.NativeUI)
598 | }
599 | $this.WrapProperty("Title", "Text", "TitleHeading")
600 | }
601 |
602 | [void] Show() {
603 | $this.DialogDiv.Style.display = "block"
604 | }
605 |
606 | [void] Hide() {
607 | $this.DialogDiv.Style.display = "none"
608 | }
609 | }
610 |
611 | class OouiTimer : OouiElement {
612 | [System.Timers.Timer] $Timer
613 | [Double] $Interval = 1000
614 |
615 | OouiTimer() {
616 | $label = [Span]::new()
617 | $label.IsHidden = $true
618 | $this.SetNativeUI($label)
619 | $this.AddScriptBlockProperty("Elapsed")
620 | $this.Timer = New-Object System.Timers.Timer
621 | Register-ObjectEvent -InputObject $this.Timer -EventName Elapsed -MessageData $this -Action {
622 | $this = $event.MessageData
623 | $this.Control.OnElapsed()
624 | }
625 | }
626 |
627 | [void] OnElapsed() {
628 | Invoke-Command -ScriptBlock $this._Elapsed -ArgumentList $this
629 | }
630 |
631 | [void] Start() {
632 | $this.Timer.Interval = $this.Interval
633 | $this.Timer.Start()
634 | }
635 |
636 | [void] Stop() {
637 | $this.Timer.Stop()
638 | }
639 | }
640 |
641 | class OouiDatePicker : OouiElement {
642 |
643 | OouiDatePicker() {
644 | $this.SetNativeUI([Input]::new("Date"))
645 | $this.AddScriptBlockProperty("Change")
646 | Register-ObjectEvent -InputObject $this.NativeUI -EventName Change -MessageData $this -Action {
647 | $this = $event.MessageData
648 | $this.Control.OnChange()
649 | } | Out-Null
650 | Add-Member -InputObject $this -Name Value -MemberType ScriptProperty -Value {
651 | [DateTime]::Parse($this.NativeUI.Value)
652 | } -SecondValue {
653 | $this.NativeUI.Value = $args[0].ToString("yyyy-MM-dd")
654 | }
655 | }
656 |
657 | [void] OnChange() {
658 | Invoke-Command -ScriptBlock $this._Change -ArgumentList $this
659 | }
660 |
661 | }
662 |
663 | class OouiTimePicker : OouiElement {
664 |
665 | OouiTimePicker() {
666 | $this.SetNativeUI([Input]::new("Time"))
667 | $this.AddScriptBlockProperty("Change")
668 | Register-ObjectEvent -InputObject $this.NativeUI -EventName Change -MessageData $this -Action {
669 | $this = $event.MessageData
670 | $this.Control.OnChange()
671 | } | Out-Null
672 | Add-Member -InputObject $this -Name Value -MemberType ScriptProperty -Value {
673 | if ($this.IsTime($this.NativeUI.Value)) {
674 | $this.NativeUI.Value
675 | } else {
676 | "00:00"
677 | }
678 | } -SecondValue {
679 | if ($this.IsTime($args[0])) {
680 | $this.NativeUI.Value = $args[0]
681 | } else {
682 | "00:00"
683 | }
684 | }
685 | }
686 |
687 | hidden [Boolean] IsTime([String] $timeText) {
688 | [DateTime] $dateTime = [DateTime]::Today
689 | return [DateTime]::TryParse( "2000-01-01 " + $timeText, [ref] $dateTime)
690 | }
691 |
692 | [void] OnChange() {
693 | Invoke-Command -ScriptBlock $this._Change -ArgumentList $this
694 | }
695 |
696 | }
697 |
698 | class OouiBrowser : OouiStackPanel {
699 | [Object[]] $Data = [Object[]] @()
700 | [int] $PageRows = 10
701 | [int] $CurrentPage = 0
702 | [Boolean] $IsEditable = $true
703 | [Object] $CurrentRow
704 |
705 | #region Components Declaration
706 |
707 | hidden [OouiListColumn[]] $Columns = [OouiListColumn[]] @()
708 | hidden [OouiListColumn] $EditionColumn
709 | hidden [OouiList] $List = [OouiList]::new()
710 | hidden [OouiStackPanel] $ButtonPanel = [OouiStackPanel]::new()
711 | hidden [OouiButton] $FirstButton = [OouiButton]::new()
712 | hidden [OouiButton] $PreviousButton = [OouiButton]::new()
713 | hidden [OouiButton] $NextButton = [OouiButton]::new()
714 | hidden [OouiButton] $LastButton = [OouiButton]::new()
715 | hidden [OouiButton] $AddNewButton = [OouiButton]::new()
716 |
717 | #endregion
718 |
719 | OouiBrowser() {
720 | $this.AddScriptBlockProperty("AddNew")
721 | $this.AddScriptBlockProperty("Edit")
722 | $this.AddScriptBlockProperty("Delete")
723 | $this.AddChild($this.List)
724 | $this.AddButtons()
725 | }
726 |
727 | #region Components Creation
728 |
729 | hidden [void] AddButtons() {
730 | $this.ButtonPanel = [OouiStackPanel]::new()
731 | $this.ButtonPanel.Orientation = "Horizontal"
732 |
733 | $this.FirstButton.Action = { $this.Parent.Parent.OnMoveFirst() }
734 | $this.PreviousButton.Action = { $this.Parent.Parent.OnMovePrevious() }
735 | $this.NextButton.Action = { $this.Parent.Parent.OnMoveNext() }
736 | $this.LastButton.Action = { $this.Parent.Parent.OnMoveLast() }
737 | $this.AddNewButton.Action = { $this.Parent.Parent.OnAddNew() }
738 |
739 | $this.ButtonPanel.AddChild($this.FirstButton)
740 | $this.ButtonPanel.AddChild($this.PreviousButton)
741 | $this.ButtonPanel.AddChild($this.NextButton)
742 | $this.ButtonPanel.AddChild($this.LastButton)
743 | $this.ButtonPanel.AddChild($this.AddNewButton)
744 |
745 | $this.StyleComponents()
746 |
747 | $this.AddChild($this.ButtonPanel)
748 | }
749 |
750 | [void] AddColumn([OouiListColumn] $listColumn) {
751 | $this.Columns += $listColumn
752 | $this.List.AddColumn($listColumn)
753 | }
754 |
755 | [void] CreateList() {
756 | $this.List.Clear()
757 | $this.CreateEditable()
758 | 0..($this.PageRows - 1) | ForEach-Object {
759 | $listItem = $this.GetInitialListItem($_)
760 | $this.List.AddItem($listItem)
761 | }
762 | }
763 |
764 | hidden [ListItem] GetInitialListItem([int] $rowIndex) {
765 | $hash = $this.GetInitialHash()
766 | $listItem = [ListItem]::new()
767 | $this.Columns | ForEach-Object {
768 | $column = $_
769 | if ($column -eq $this.EditionColumn -and $this.IsEditable) {
770 | $this.AddEditionButtons($hash, $listItem, $rowIndex)
771 | } else {
772 | $this.AddCell($hash, $column.Name, $listItem, $rowIndex)
773 | }
774 | }
775 | return $listItem
776 | }
777 |
778 | hidden [Object] GetInitialHash() {
779 | $hash = @{}
780 | $this.Columns | ForEach-Object {
781 | $column = $_
782 | $hash += @{ "$($column.Name)" = "" }
783 | }
784 | return $hash
785 | }
786 |
787 | hidden [void] AddEditionButtons([Object] $hash, [ListItem] $listItem, [int] $rowIndex) {
788 | $editionPanel = [OouiStackPanel]::new()
789 | $editionPanel.Orientation = "Horizontal"
790 | $listItem.AddChild($editionPanel)
791 |
792 | $editButton = [OouiButton]::new()
793 | Add-Member -InputObject $editButton -MemberType NoteProperty -Name CurrentRow -Value $hash
794 | Add-Member -InputObject $editButton -MemberType NoteProperty -Name Container -Value $this
795 | $editButton.Action = {
796 | $this.Container.CurrentRow = $this.Control.CurrentRow
797 | $this.Container.OnEdit()
798 | }
799 | $editionPanel.AddChild($editButton)
800 |
801 | $deleteButton = [OouiButton]::new()
802 | Add-Member -InputObject $deleteButton -MemberType NoteProperty -Name CurrentRow -Value $hash
803 | Add-Member -InputObject $deleteButton -MemberType NoteProperty -Name Container -Value $this
804 | $deleteButton.Action = {
805 | $this.Container.CurrentRow = $this.Control.CurrentRow
806 | $this.Container.OnDelete()
807 | }
808 | $editionPanel.AddChild($deleteButton)
809 | $this.StyleEditionButtons($editButton, $deleteButton, $rowIndex)
810 | }
811 |
812 | hidden [void] AddCell([Object] $hash, [string] $columnName, [ListItem] $listItem, [int] $rowIndex) {
813 | $itemLabel = [OouiLabel]::new()
814 | $itemLabel.Caption = $hash."$columnName"
815 | $listItem.AddChild($itemLabel)
816 | $this.StyleCell($itemLabel, $rowIndex)
817 | }
818 |
819 | hidden [void] CreateEditable() {
820 | if ($this.EditionColumn -eq $null -and $this.IsEditable) {
821 | $this.CreateEditionColumn()
822 | }
823 | $this.AddNewButton.Visible = $this.IsEditable
824 | }
825 |
826 | hidden [void] CreateEditionColumn() {
827 | $this.EditionColumn = New-Object OouiListColumn -Property @{Name = "_Edition"; Title = "_"}
828 | $this.AddColumn($this.EditionColumn)
829 | }
830 |
831 | #endregion
832 |
833 | #region Data show
834 |
835 | [void] Refresh() {
836 | # Fill Rows
837 | $rowIndex = 0
838 | $selectedData = $this.GetSelectedData()
839 | $selectedData | ForEach-Object {
840 | $hash = $_
841 | $columnIndex = 0
842 | $this.Columns | Select-Object -First ($this.Columns.Count) | ForEach-Object {
843 | $column = $_
844 | $cell = $this.List.GetCell($rowIndex, $columnIndex)
845 | if ($this.EditionColumn -ne $column) {
846 | $cell.Children.Item(0).Text = $hash."$($column.Name)"
847 | } else {
848 | $cell.IsHidden = $false
849 | #$buttons = $this.List.Children.Item($columnIndex).Children.Item($rowIndex + 1).Children
850 | #$buttons.Item(0).CurrentRow = $hash
851 | #$buttons.Item(1).CurrentRow = $hash
852 | $stack = $cell.Children.Item(0)
853 | $stack.Control.Children.Item(0).CurrentRow = $hash
854 | $stack.Control.Children.Item(1).CurrentRow = $hash
855 | }
856 | $columnIndex++
857 | }
858 | $rowIndex++
859 | }
860 | # EmptyRows
861 | for ($rowIndex = $selectedData.Count + 1; $rowIndex -le $this.PageRows; $rowIndex++) {
862 | $columnIndex = 0
863 | $this.Columns | Select-Object -First ($this.Columns.Count) | ForEach-Object {
864 | $cell = $this.List.GetCell($rowIndex - 1, $columnIndex)
865 | $column = $_
866 | if ($this.EditionColumn -ne $column) {
867 | $cell.Children.Item(0).Text = ""
868 | } else {
869 | $cell.IsHidden = $true
870 | }
871 | $columnIndex++
872 | }
873 | }
874 | }
875 |
876 | hidden [Object[]] GetSelectedData() {
877 | return $this.Data | Select-Object -Skip ($this.CurrentPage * $this.PageRows) -First $this.PageRows
878 | }
879 |
880 | hidden [int] GetLastPage() {
881 | $lastPage = [Math]::Truncate($this.Data.Count / $this.PageRows)
882 | if (($this.Data.Count % $this.PageRows) -eq 0) {
883 | $lastPage--
884 | }
885 | return $lastPage
886 | }
887 |
888 | #endregion
889 |
890 | #region Style
891 |
892 | [void] StyleComponents() {
893 | $this.List.NativeUI.ClassName = "UIList table"
894 |
895 | $this.FirstButton.Icon = [OouiIcon] @{ Kind = "first_page" }
896 | $this.PreviousButton.Icon = [OouiIcon] @{ Kind = "chevron_left" }
897 | $this.NextButton.Icon = [OouiIcon] @{ Kind = "chevron_right" }
898 | $this.LastButton.Icon = [OouiIcon] @{ Kind = "last_page" }
899 | $this.AddNewButton.Icon = [OouiIcon] @{ Kind = "add" }
900 |
901 | $this.FirstButton.NativeUI.ClassName = "btn btn-link"
902 | $this.PreviousButton.NativeUI.ClassName = "btn btn-link"
903 | $this.NextButton.NativeUI.ClassName = "btn btn-link"
904 | $this.LastButton.NativeUI.ClassName = "btn btn-link"
905 | $this.AddNewButton.NativeUI.ClassName = "btn btn-link"
906 | }
907 |
908 | [void] StyleCell($cell, [int] $rowIndex) {
909 | }
910 |
911 | [void] StyleEditionButtons([OouiButton] $editButton, [OouiButton] $deleteButton, [int] $rowIndex) {
912 | $editButton.Icon = [OouiIcon] @{ Kind = "edit" }
913 | $deleteButton.Icon = [OouiIcon] @{ Kind = "close" }
914 |
915 | $editButton.NativeUI.ClassName = "btn btn-success td-actions btn-sm"
916 | $deleteButton.NativeUI.ClassName = "btn btn-danger td-actions btn-sm"
917 | }
918 |
919 | #endregion
920 |
921 | #region Move Events
922 |
923 | hidden [void] OnMoveFirst() {
924 | $this.CurrentPage = 0
925 | $this.Refresh()
926 | }
927 |
928 | hidden [void] OnMovePrevious() {
929 | if ($this.CurrentPage -gt 0) {
930 | $this.CurrentPage--
931 | }
932 | $this.Refresh()
933 | }
934 |
935 | hidden [void] OnMoveNext() {
936 | if ($this.CurrentPage -lt $this.GetLastPage()) {
937 | $this.CurrentPage++
938 | }
939 | $this.Refresh()
940 | }
941 |
942 | hidden [void] OnMoveLast() {
943 | $this.CurrentPage = $this.GetLastPage()
944 | $this.Refresh()
945 | }
946 |
947 | #endregion
948 |
949 | #region CRUD Events
950 |
951 | hidden [void] OnAddNew() {
952 | $this.InvokeTrappableCommand($this._AddNew, $this)
953 | }
954 |
955 | hidden [void] OnEdit() {
956 | $this.InvokeTrappableCommand($this._Edit, $this)
957 | }
958 |
959 | hidden [void] OnDelete() {
960 | $this.InvokeTrappableCommand($this._Delete, $this)
961 | }
962 |
963 | #endregion
964 |
965 | }
966 |
967 | class OouiMenuItem : OouiButton {
968 |
969 | [void] OnAction() {
970 | ([OouiButton]$this).OnAction()
971 | $this.Parent.ToogleMenu()
972 | }
973 |
974 | }
975 |
976 | class OouiDropDownMenu : OouiStackPanel {
977 |
978 | [OOuiButton] $DropDownToogle = [OOuiButton]::new()
979 | [List] $DropDownMenu = [List]::new()
980 |
981 | OouiDropDownMenu() {
982 | $dropDown = [Div]::new()
983 | $dropDown.SetAttribute("class", "dropdown")
984 | $this.NativeUI.AppendChild($dropDown)
985 |
986 | $this.DropDownToogle.NativeUI.SetAttribute("class", "btn btn-primary dropdown-toggle")
987 | $this.DropDownToogle.NativeUI.SetAttribute("data-toggle", "dropdown")
988 | $this.DropDownToogle.NativeUI.SetAttribute("aria-expanded", "true")
989 | $this.DropDownToogle.NativeUI.SetAttribute("aria-haspopup", "true")
990 | Add-Member -InputObject $this.DropDownToogle -MemberType NoteProperty -Name ParentControl -Value $this
991 | $this.DropDownToogle.Action = {
992 | param ($this)
993 | $this.Control.ParentControl.ToogleMenu()
994 | }
995 | $dropDown.AppendChild($this.DropDownToogle.NativeUI)
996 |
997 | $this.DropDownMenu.SetAttribute("class", "dropdown-menu")
998 | $dropDown.AppendChild($this.DropDownMenu)
999 |
1000 | $this.AddNativeUIChild = {
1001 | param (
1002 | [OouiElement] $element
1003 | )
1004 | $menuItem = [Ooui.ListItem]::new()
1005 | $element.NativeUI.SetAttribute("class", "dropdown-item")
1006 | $element.NativeUI.Style.Width = "100%"
1007 | $element.NativeUI.Style.BorderColor = "transparent"
1008 | $menuItem.AppendChild($element.NativeUI) | Out-Null
1009 | $this.DropDownMenu.AppendChild($menuItem) | Out-Null
1010 | }
1011 | $this.RemoveNativeUIChild = {
1012 | param (
1013 | [OouiElement] $element
1014 | )
1015 | $this.DropDownMenu.Children | ForEach-Object {
1016 | if ($_.Children.Item(0) -eq $element.NativeUI) {
1017 | $this.DropDownMenu.RemoveChild($_) | Out-Null
1018 | }
1019 | }
1020 | }
1021 | Add-Member -InputObject $this -Name "Caption" -MemberType ScriptProperty `
1022 | -Value { $this.DropDownToogle.NativeUI.Text } `
1023 | -SecondValue { $this.DropDownToogle.NativeUI.Text = $args[0] }
1024 | }
1025 |
1026 | [void] ToogleMenu() {
1027 | if ($this.DropDownMenu.ClassName.Contains("show")) {
1028 | $this.DropDownMenu.ClassName = $this.DropDownMenu.ClassName.Replace(" show", "")
1029 | } else {
1030 | $this.DropDownMenu.ClassName = $this.DropDownMenu.ClassName + " show"
1031 | }
1032 | }
1033 |
1034 | }
1035 |
1036 | class OouiAutoComplete : OouiStackPanel {
1037 |
1038 | [OouiTextBox] $TextBox = [OouiTextBox]::new()
1039 | [List] $DropDownMenu = [List]::new()
1040 |
1041 | OouiAutoComplete() {
1042 | $dropDown = [Div]::new()
1043 | $dropDown.SetAttribute("class", "dropdown")
1044 | $this.NativeUI.AppendChild($dropDown)
1045 |
1046 | $this.TextBox.NativeUI.SetAttribute("class", "dropdown-toggle")
1047 | $this.TextBox.NativeUI.SetAttribute("data-toggle", "dropdown")
1048 | $this.TextBox.NativeUI.SetAttribute("aria-expanded", "true")
1049 | $this.TextBox.NativeUI.SetAttribute("aria-haspopup", "true")
1050 | Add-Member -InputObject $this.TextBox -MemberType NoteProperty -Name ParentControl -Value $this
1051 | $this.TextBox.Change = {
1052 | param ($this)
1053 | $this.Control.ParentControl.ClearDropDown()
1054 | }
1055 | Register-ObjectEvent -InputObject $this.TextBox.NativeUI -EventName KeyDown -MessageData $this -Action {
1056 | $this = $event.MessageData
1057 | #$this.Control.TextBox.Text = $event.SourceArgs[1]
1058 | } | Out-Null
1059 | Register-ObjectEvent -InputObject $this.TextBox.NativeUI -EventName KeyUp -MessageData $this -Action {
1060 | $this = $event.MessageData
1061 | $this.Control.ShowDropDown()
1062 | } | Out-Null
1063 | $dropDown.AppendChild($this.TextBox.NativeUI)
1064 |
1065 | $this.DropDownMenu.SetAttribute("class", "dropdown-menu")
1066 | $dropDown.AppendChild($this.DropDownMenu)
1067 |
1068 | $this.AddNativeUIChild = {
1069 | param (
1070 | [OouiElement] $element
1071 | )
1072 | $menuItem = [Ooui.ListItem]::new()
1073 | #$element.NativeUI.SetAttribute("class", "btn btn-default")
1074 | $element.NativeUI.SetAttribute("class", "dropdown-item")
1075 | $element.NativeUI.Style.Width = "100%"
1076 | $element.NativeUI.Style.BorderColor = "transparent"
1077 | $menuItem.AppendChild($element.NativeUI) | Out-Null
1078 | $this.DropDownMenu.AppendChild($menuItem) | Out-Null
1079 | }
1080 | Add-Member -InputObject $this -Name "Text" -MemberType ScriptProperty `
1081 | -Value { $this.TextBox.Text } `
1082 | -SecondValue { $this.TextBox.Text = $args[0] }
1083 | $this.AddScriptBlockProperty("ItemsRequested")
1084 | }
1085 |
1086 | [void] ShowDropDown() {
1087 | $this.ClearDropDown()
1088 | $this.AddItems()
1089 | if (-not $this.DropDownMenu.ClassName.Contains("show")) {
1090 | $this.DropDownMenu.ClassName = $this.DropDownMenu.ClassName + " show"
1091 | }
1092 | }
1093 |
1094 | [void] ClearDropDown() {
1095 | $this.DropDownMenu.Children | ForEach-Object {
1096 | $this.DropDownMenu.RemoveChild($_)
1097 | }
1098 | if ($this.DropDownMenu.ClassName.Contains("show")) {
1099 | $this.DropDownMenu.ClassName = $this.DropDownMenu.ClassName.Replace(" show", "")
1100 | }
1101 | }
1102 |
1103 | [void] AddItems() {
1104 | $this.OnItemsRequested()
1105 | }
1106 |
1107 | [void] OnItemsRequested() {
1108 | [AutoCompleteItem[]] $items = Invoke-Command -ScriptBlock $this._ItemsRequested -ArgumentList $this
1109 | $items | ForEach-Object {
1110 | [OOuiButton] $button = [OOuiButton] @{ Caption = $_.Text }
1111 | Add-Member -InputObject $button -MemberType NoteProperty -Name AutoCompleteTextBox -Value $this.TextBox
1112 | Add-Member -InputObject $button -MemberType NoteProperty -Name AutoCompleteId -Value $_.Id
1113 | $button.Action = {
1114 | param ($this)
1115 | $this.Control.AutoCompleteTextBox.Text = $this.Control.AutoCompleteId
1116 | }
1117 | $this.AddChild($button)
1118 | }
1119 | }
1120 |
1121 | }
1122 |
1123 | class OouiCard : OouiElement {
1124 | hidden [div] $CardContainerDiv = [div]::new()
1125 | hidden [div] $CardHeaderDiv = [div]::new()
1126 | hidden [div] $CardIconDiv = [div]::new()
1127 | hidden [OouiStackPanel] $CardBodyDiv = [OouiStackPanel]::new()
1128 | hidden [icon] $CardIcon = [icon]::new()
1129 | hidden [Heading] $Header = [Heading]::new(4)
1130 |
1131 | hidden [OOuiIcon] $CurrentIcon = $null
1132 |
1133 | OouiCard() {
1134 | $this.SetNativeUI($this.CardContainerDiv)
1135 | $this.CardContainerDiv.AppendChild($this.CardHeaderDiv)
1136 | $this.CardContainerDiv.AppendChild($this.CardBodyDiv.NativeUI)
1137 | $this.CardHeaderDiv.AppendChild($this.CardIconDiv)
1138 | $this.CardHeaderDiv.AppendChild($this.Header)
1139 | $this.CardIconDiv.AppendChild($this.CardIcon)
1140 |
1141 | $this.WrapProperty("Caption", "Text", "Header")
1142 | Add-Member -InputObject $this -Name Icon -MemberType ScriptProperty -Value {
1143 | $this.CurrentIcon
1144 | } -SecondValue {
1145 | $this.CurrentIcon = $args[0]
1146 | if ($this.CurrentIcon -ne $null) {
1147 | $this.CardIcon.Text = $this.CurrentIcon.NativeUI.Text
1148 | } else {
1149 | $this.CardIcon.Text = ""
1150 | }
1151 | }
1152 | $this.AddNativeUIChild = {
1153 | param (
1154 | [OouiElement] $element
1155 | )
1156 | $listItem = [Div]::new()
1157 | if ($this.CardBodyDiv.Orientation -eq [Orientation]::Horizontal) {
1158 | $listItem.Style.float = "left"
1159 | } else {
1160 | $listItem.Style.clear = "both"
1161 | }
1162 | $this.CardBodyDiv.NativeUI.AppendChild($listItem) | Out-Null
1163 | $listItem.AppendChild($element.NativeUI) | Out-Null
1164 | }
1165 | $this.StyleComponents()
1166 | }
1167 |
1168 | [void] StyleComponents() {
1169 | $this.CardContainerDiv.ClassName = "card"
1170 | $this.Header.ClassName = "card-title"
1171 | $this.Header.Style.display = "inline"
1172 | $this.CardHeaderDiv.ClassName = "card-header card-header-icon "
1173 | $this.CardIconDiv.ClassName = "card-icon"
1174 | $this.CardIcon.ClassName = "material-icons"
1175 | $this.CardBodyDiv.NativeUI.ClassName = "card-body"
1176 | $this.CardBodyDiv.Orientation = [Orientation]::Vertical
1177 | }
1178 | }
1179 |
1180 | class OouiImage : OouiElement {
1181 |
1182 | OouiImage() {
1183 | $image = [Image]::new()
1184 | $this.SetNativeUI($image)
1185 | $this.WrapProperty("Source", "Source")
1186 | Add-Member -InputObject $this -Name Width -MemberType ScriptProperty -Value {
1187 | $this.NativeUI.Style.width
1188 | } -SecondValue {
1189 | $this.NativeUI.Style.width = $args[0]
1190 | }
1191 | }
1192 | }
1193 |
1194 | class OouiTextEditor : OouiElement {
1195 |
1196 | OouiTextEditor() {
1197 | $this.SetNativeUI([TextArea]::new())
1198 | $this.WrapProperty("Text", "Value")
1199 | $this.AddScriptBlockProperty("Change")
1200 | Add-Member -InputObject $this -Name Height -MemberType ScriptProperty -Value {
1201 | [int] $this.NativeUI.Rows
1202 | } -SecondValue {
1203 | $this.NativeUI.Rows = $args[0]
1204 | }
1205 | Add-Member -InputObject $this -Name Width -MemberType ScriptProperty -Value {
1206 | [int] $this.NativeUI.Columns
1207 | } -SecondValue {
1208 | $this.NativeUI.Columns = $args[0]
1209 | }
1210 |
1211 | Register-ObjectEvent -InputObject $this.NativeUI -EventName Change -MessageData $this -Action {
1212 | $this = $event.MessageData
1213 | $this.Control.OnChange()
1214 | } | Out-Null
1215 | }
1216 |
1217 | [void] OnChange() {
1218 | Invoke-Command -ScriptBlock $this._Change -ArgumentList $this
1219 | }
1220 | }
1221 |
1222 | class OouiExpander : OouiElement {
1223 | hidden [div] $AcordionDiv = [div] @{ ClassName = "accordion" }
1224 | hidden [div] $AcodionItemDiv = [div] @{ ClassName = "accordion-item" }
1225 | hidden [Heading] $AccordionHeader = [Heading]::new(2)
1226 | hidden [Button] $AccordionButton = [Button] @{ ClassName = "accordion-button" }
1227 | hidden [div] $AccordionCollapseDiv = [div] @{ ClassName = "accordion-collapse collapse show" }
1228 | hidden [OouiStackPanel] $Body = [OouiStackPanel]::new()
1229 |
1230 | OouiExpander() {
1231 | $this.SetNativeUI($this.AcordionDiv)
1232 | $this.AcordionDiv.AppendChild($this.AcodionItemDiv)
1233 | $this.AccordionHeader.ClassName = "accordion-header"
1234 | $this.AcodionItemDiv.AppendChild($this.AccordionHeader)
1235 | $this.AccordionButton.SetAttribute("data-bs-toggle", "collapse")
1236 | $this.AccordionButton.SetAttribute("data-bs-target", "#$($this.AccordionCollapseDiv.Id)")
1237 | $this.AccordionButton.SetAttribute("aria-expanded", "true")
1238 | $this.AccordionButton.SetAttribute("aria-controls", $this.AccordionCollapseDiv.Id)
1239 | $this.AccordionHeader.AppendChild($this.AccordionButton)
1240 | #$this.AccordionCollapseDiv.SetAttribute("data-bs-parent", "#$($this.AcordionDiv.Id)")
1241 | $this.AcodionItemDiv.AppendChild($this.AccordionCollapseDiv)
1242 | $this.Body.NativeUI.ClassName = "accordion-body"
1243 | $this.AccordionCollapseDiv.AppendChild($this.Body.NativeUI)
1244 |
1245 | $this.WrapProperty("Caption", "Text", "AccordionButton")
1246 |
1247 | $this.AddNativeUIChild = {
1248 | param (
1249 | [OouiElement] $element
1250 | )
1251 | $listItem = [Div]::new()
1252 | if ($this.Body.Orientation -eq [Orientation]::Horizontal) {
1253 | $listItem.Style.float = "left"
1254 | } else {
1255 | $listItem.Style.clear = "both"
1256 | }
1257 | $this.Body.NativeUI.AppendChild($listItem) | Out-Null
1258 | $listItem.AppendChild($element.NativeUI) | Out-Null
1259 | }
1260 | }
1261 |
1262 | }
1263 |
1264 | class OouiInteger : OouiTextBox {
1265 |
1266 | OouiInteger() {
1267 | $this.TextAlignment = [TextAlignment]::Right
1268 | $this.Pattern = '^[\d]+$'
1269 | $this.DefaultText = "0"
1270 | $this.Text = "0"
1271 | }
1272 | }
1273 |
1274 | class OouiDouble : OouiTextBox {
1275 |
1276 | OouiDouble() {
1277 | $this.TextAlignment = [TextAlignment]::Right
1278 | $this.Pattern = '^[\d\.]+$'
1279 | $this.DefaultText = "0.0"
1280 | $this.Text = "0.0"
1281 | }
1282 | }
1283 |
1284 | #region ComboBox with Select
1285 | #class OouiComboBoxItem : OouiElement {
1286 | #
1287 | # OouiComboBoxItem() {
1288 | # $this.SetNativeUI([Option]::new())
1289 | # $this.WrapProperty("Id" , "Value")
1290 | # $this.WrapProperty("Caption", "Label")
1291 | # }
1292 | #}
1293 | #
1294 | #class OouiComboBox : OouiElement {
1295 | #
1296 | # OouiComboBox() {
1297 | # $this.SetNativeUI([Select]::new())
1298 | # Add-Member -InputObject $this -Name Text -MemberType ScriptProperty -Value {
1299 | # $this.NativeUI.Value
1300 | # } -SecondValue {
1301 | # $id = [String] $Args[0]
1302 | # $this.NativeUI.value = $id
1303 | # #$selectedItem = $this.NativeUI.Children | Where-Object { $_.Value -eq $id }
1304 | # #if ($selectedItem -ne $null) {
1305 | # # $this.NativeUI.Value = $id
1306 | # # $selectedItem.DefaultSelected = $true
1307 | # #}
1308 | # }
1309 | # $this.AddScriptBlockProperty("Change")
1310 | # Register-ObjectEvent -InputObject $this.NativeUI -EventName Change -MessageData $this -Action {
1311 | # $this = $event.MessageData
1312 | # $this.Control.OnChange()
1313 | # } | Out-Null
1314 | # $this.AddNativeUIChild = {
1315 | # param (
1316 | # [OouiElement] $element
1317 | # )
1318 | # $this.NativeUI.AppendChild($element.NativeUI)
1319 | # }
1320 | # }
1321 | #
1322 | # [void] OnChange() {
1323 | # $this.InvokeTrappableCommand($this._Change, $this)
1324 | # }
1325 | #
1326 | #}
1327 | #endregion
1328 |
1329 | class OouiComboBoxItem : OouiMenuItem {
1330 | [String] $Id
1331 |
1332 | OouiComboBoxItem() {
1333 | }
1334 | }
1335 |
1336 | class OouiCombobox : OouiDropDownMenu {
1337 | [String] $SelectedId
1338 | [String] $BackgroundColor = "transparent"
1339 | [String] $Color = "black"
1340 |
1341 | OouiCombobox() {
1342 | Add-Member -InputObject $this -Name Text -MemberType ScriptProperty -Value {
1343 | $this.SelectedId
1344 | } -SecondValue {
1345 | $id = $args[0]
1346 | if ($this.SelectedId -ne $id) {
1347 | $selectedItem = $this.Children | Where-Object { $_.Id -eq $id }
1348 | if ($selectedItem -ne $null) {
1349 | $this.DropDownToogle.Caption = $selectedItem.Caption
1350 | $this.SelectedId = $id
1351 | $this.Control.OnChange()
1352 | }
1353 | }
1354 | }
1355 | $this.AddScriptBlockProperty("Change")
1356 | $this.AddNativeUIChild = {
1357 | param (
1358 | [OouiElement] $element
1359 | )
1360 | $menuItem = [Ooui.ListItem]::new()
1361 | $element.NativeUI.SetAttribute("class", "dropdown-item")
1362 | $element.NativeUI.Style.Width = "100%"
1363 | $element.NativeUI.Style.BorderColor = "transparent"
1364 | Add-Member -InputObject $element -MemberType NoteProperty -Name ComboBox -Value $this
1365 | $element.Action = {
1366 | param ($this)
1367 | $this.ComboBox.Text = $this.Id
1368 | }
1369 | $menuItem.AppendChild($element.NativeUI) | Out-Null
1370 | $this.DropDownMenu.AppendChild($menuItem) | Out-Null
1371 | }
1372 | $this.StyleComponents()
1373 | }
1374 |
1375 | [void] OnChange() {
1376 | Invoke-Command -ScriptBlock $this._Change -ArgumentList $this
1377 | }
1378 |
1379 | [void] StyleComponents () {
1380 | $this.DropDownToogle.NativeUI.Style.BackgroundColor = $this.BackgroundColor
1381 | $this.DropDownToogle.NativeUI.Style.Color = $this.Color
1382 | }
1383 |
1384 | }
1385 |
1386 | class OouiFileUpload : OouiElement {
1387 | [Anchor] $Anchor = [Anchor] @{ Href = "/files"; Target = "_blank" }
1388 | hidden [Span] $LabelNativeUI = [Span]::new()
1389 |
1390 | OouiFileUpload() {
1391 | $this.SetNativeUI($this.Anchor)
1392 | $this.WrapProperty("Caption", "Text", "LabelNativeUI")
1393 | $this.NativeUI.AppendChild($this.LabelNativeUI)
1394 | }
1395 |
1396 | }
--------------------------------------------------------------------------------
/UIfied/UIfiedWPFBase.ps1:
--------------------------------------------------------------------------------
1 | using namespace System.Collections.Generic
2 | using namespace System.Windows
3 | using namespace System.Windows.Controls
4 | using namespace System.Windows.Input
5 |
6 | class WPFElement : UIElement {
7 |
8 | WPFElement() {
9 | $this.WrapProperty("Enable", "IsEnabled")
10 | Add-Member -InputObject $this -Name Visible -MemberType ScriptProperty -Value {
11 | $this.NativeUI.Visibility -eq [Visibility]::Visible
12 | } -SecondValue {
13 | if ($args[0]) {
14 | $this.NativeUI.Visibility = [Visibility]::Visible
15 | } else {
16 | $this.NativeUI.Visibility = [Visibility]::Collapsed
17 | }
18 | }
19 | $this.AddNativeUIChild = {
20 | param (
21 | [WPFElement] $element
22 | )
23 | $this.NativeUI.AddChild($element.NativeUI) | Out-Null
24 | }
25 | $this.RemoveNativeUIChild = {
26 | param (
27 | [WPFElement] $element
28 | )
29 | $this.NativeUI.Children.Remove($element.NativeUI) | Out-Null
30 | }
31 | $this.ShowError = {
32 | param (
33 | [Object] $errorObject
34 | )
35 | [MessageBox]::Show($errorObject)
36 | }
37 | }
38 |
39 | }
40 |
41 | class WPFHost : UIHost {
42 | [HashTable] $SyncHash
43 |
44 | [void] ShowFrame([ScriptBlock] $frameScriptBlock) {
45 | $this.SyncHash = [HashTable]::Synchronized(@{})
46 | $this.SyncHash.Errors = @()
47 | $Global:SyncHash = $this.SyncHash
48 |
49 | $Window = Invoke-Command -ScriptBlock $frameScriptBlock
50 | $window.ShowDialog()
51 | }
52 | }
53 |
54 | class WPFWindow : WindowBase {
55 | [Application] $Application = [System.Windows.Application]::new()
56 | [Window] $windowNativeUI = [Window]::new()
57 |
58 | WPFWindow() {
59 | $this.StyleApplication()
60 | $this.windowNativeUI.SizeToContent = 'WidthAndHeight'
61 | $this.windowNativeUI.Margin = 10
62 | $this.Application.MainWindow = $this.windowNativeUI
63 |
64 | $this.SetNativeUI($this.windowNativeUI)
65 | $this.WrapProperty("Caption", "Title")
66 | $this.AddScriptBlockProperty("Loaded")
67 | $this.AddNativeUIChild = {
68 | param (
69 | [WPFElement] $element
70 | )
71 | $this.NativeUI.Content = $element.NativeUI
72 | }
73 | $this.StyleCOmponents()
74 | }
75 |
76 | [void] StyleApplication() {
77 | }
78 |
79 | [void] StyleComponents() {
80 | }
81 |
82 | [void] ShowDialog() {
83 | $this.NativeUI.ShowDialog()
84 | }
85 |
86 | [void] OnLoaded() {
87 | Invoke-Command -ScriptBlock $this._Loaded -ArgumentList $this
88 | }
89 |
90 | }
91 |
92 | class WPFStackPanel : WPFElement {
93 |
94 | WPFStackPanel() {
95 | $this.SetNativeUI([StackPanel]::new())
96 | $this.WrapProperty("Orientation", "Orientation")
97 | }
98 | }
99 |
100 | class WPFLabel : WPFElement {
101 |
102 | WPFLabel() {
103 | $this.SetNativeUI([Label]::new())
104 | $this.WrapProperty("Caption", "Content")
105 | }
106 | }
107 |
108 | class WPFIcon : WPFLabel {
109 | hidden [String] $KindName
110 |
111 | WPFIcon() {
112 | Add-Member -InputObject $this -Name Kind -MemberType ScriptProperty -Value {
113 | $this.KindName
114 | } -SecondValue {
115 | $this.KindName = $args[0]
116 | $this.RefreshCaption()
117 | }
118 | }
119 |
120 | [void] RefreshCaption() {
121 | $this.Caption = [IconStrinfy]::ToIconString($this.KindName)
122 | }
123 | }
124 |
125 | class WPFButton : WPFElement {
126 | hidden [String] $CaptionText = ""
127 | hidden [String] $IconText = ""
128 | [bool] $RightIcon = $false
129 |
130 | WPFButton() {
131 | $this.SetNativeUI([Button]::new())
132 | Add-Member -InputObject $this -Name Caption -MemberType ScriptProperty -Value {
133 | $this.CaptionText
134 | } -SecondValue {
135 | $this.CaptionText = $args[0]
136 | $this.RefreshCaption()
137 | }
138 | Add-Member -InputObject $this -Name Icon -MemberType ScriptProperty -Value {
139 | $this.IconText
140 | } -SecondValue {
141 | if ($args[0] -ne $null) {
142 | $this.IconText = [IconStrinfy]::ToIconString($args[0].Kind)
143 | $this.RefreshCaption()
144 | } else {
145 | $this.IconText = ""
146 | $this.RefreshCaption()
147 | }
148 | }
149 | $this.AddScriptBlockProperty("Action")
150 | $this.NativeUI.Add_Click({ $this.Control.OnAction() })
151 | }
152 |
153 | [void] RefreshCaption() {
154 | if ($this.RightIcon) {
155 | $this.NativeUI.Content = ($this.CaptionText + " " + $this.IconText).Trim()
156 | } else {
157 | $this.NativeUI.Content = ($this.IconText + " " + $this.CaptionText).Trim()
158 | }
159 | }
160 |
161 | [void] OnAction() {
162 | $this.InvokeTrappableCommand($this._Action, $this)
163 | }
164 | }
165 |
166 | class WPFTextBox : WPFElement {
167 | [String] $Pattern = ""
168 | [String] $DefaultText = ""
169 |
170 | WPFTextBox() {
171 | $this.SetNativeUIControl()
172 | $this.AddScriptBlockProperty("Change")
173 | $this.NativeUI.Add_LostFocus({
174 | if ($this.Control.Pattern -ne "") {
175 | $regex = [Regex]::new($this.Control.Pattern)
176 | if (-not $regex.IsMatch($this.Control.Text)) {
177 | $this.Control.Text = $this.Control.DefaultText
178 | }
179 | }
180 | })
181 | }
182 |
183 | [void] SetNativeUIControl() {
184 | $this.SetNativeUI([TextBox]::new())
185 | $this.WrapProperty("Text", "Text")
186 | $this.WrapProperty("TextAlignment", "TextAlignment")
187 | $this.NativeUI.Add_TextChanged({ $this.Control.OnChange() })
188 | }
189 |
190 | [void] OnChange() {
191 | $this.InvokeTrappableCommand($this._Change, $this)
192 | }
193 |
194 | }
195 |
196 | class WPFPassword : WPFTextBox {
197 |
198 | [void] SetNativeUIControl() {
199 | $this.SetNativeUI([PasswordBox]::new())
200 | $this.WrapProperty("Text", "Password")
201 | $this.NativeUI.Add_PasswordChanged({ $this.Control.OnChange() })
202 | }
203 |
204 | }
205 |
206 | class WPFCheckBox : WPFElement {
207 |
208 | WPFCheckBox() {
209 | $this.SetNativeUI([CheckBox]::new())
210 | $this.WrapProperty("Caption", "Content")
211 | $this.WrapProperty("IsChecked", "IsChecked")
212 | $this.AddScriptBlockProperty("Click")
213 | $this.NativeUI.Add_Click({ $this.Control.OnClick() })
214 | }
215 |
216 | [void] OnClick() {
217 | $this.InvokeTrappableCommand($this._Click, $this)
218 | }
219 |
220 | }
221 |
222 | class WPFRadioButton : WPFElement {
223 |
224 | WPFRadioButton() {
225 | $this.SetNativeUI([RadioButton]::new())
226 | $this.WrapProperty("Caption", "Content")
227 | $this.WrapProperty("IsChecked", "IsChecked")
228 | $this.AddScriptBlockProperty("Click")
229 | $this.NativeUI.Add_Click({ $this.Control.OnClick() })
230 | }
231 |
232 | [void] OnClick() {
233 | $this.InvokeTrappableCommand($this._Click, $this)
234 | }
235 |
236 | }
237 |
238 | class WPFRadioGroup : WPFElement {
239 | hidden $StackPanel
240 |
241 | WPFRadioGroup() {
242 | $this.SetNativeUI([GroupBox]::new())
243 | $this.StackPanel = [StackPanel]::new()
244 | $this.NativeUI.Content = $this.StackPanel
245 | $this.AddNativeUIChild = {
246 | param (
247 | [WPFElement] $element
248 | )
249 | $this.StackPanel.AddChild($element.NativeUI)
250 | }
251 | }
252 |
253 | }
254 |
255 | class WPFList : WPFStackPanel {
256 | [List[ListItem]] $Items = [List[ListItem]]::new()
257 |
258 | WPFList() {
259 | $this.Orientation = [Orientation]::Horizontal
260 | }
261 |
262 | [void] AddColumn([WPFListColumn] $listColumn) {
263 | $column = [WPFStackPanel]::new()
264 | $column.Orientation = [Orientation]::Vertical
265 | $title = [WPFLabel]::new()
266 | $title.Caption = $listColumn.Title
267 | $column.AddChild($title)
268 | $this.AddChild($column)
269 | }
270 |
271 | [void] AddItem([ListItem] $listItem) {
272 | $this.Items.Add($listItem)
273 | $columnIndex = 0
274 | $this.Children | ForEach-Object {
275 | $column = $_
276 | $cell = $listItem.Children.Item($columnIndex)
277 | $cell.NativeUI.Height = 25
278 | $column.AddChild($cell)
279 | $columnIndex++
280 | }
281 | }
282 |
283 | [void] RemoveItem([ListItem] $listItem) {
284 | $this.Items.Remove($listItem)
285 | $columnIndex = 0
286 | $this.Children | ForEach-Object {
287 | $column = $_
288 | $cell = $listItem.Children.Item($columnIndex)
289 | $column.RemoveChild($cell)
290 | $columnIndex++
291 | }
292 | }
293 |
294 | [void] Clear() {
295 | $this.Items.ToArray() | ForEach-Object {
296 | $this.RemoveItem($_)
297 | }
298 | }
299 | }
300 |
301 | class WPFListColumn {
302 | [String] $Name
303 | [String] $Title
304 | }
305 |
306 | class WPFTabItem : WPFElement {
307 | hidden $StackPanelNativeUI
308 |
309 | WPFTabItem() {
310 | $this.SetNativeUI([TabItem]::new())
311 | $this.StackPanelNativeUI = [StackPanel]::new()
312 | $this.NativeUI.Content = $this.StackPanelNativeUI
313 | $this.WrapProperty("Caption", "Header")
314 | $this.AddNativeUIChild = {
315 | param (
316 | [WPFElement] $element
317 | )
318 | $this.StackPanelNativeUI.AddChild($element.NativeUI) | Out-Null
319 | }
320 | }
321 |
322 | }
323 |
324 | class WPFTabControl : WPFElement {
325 |
326 | WPFTabControl() {
327 | $this.SetNativeUI([TabControl]::new())
328 | }
329 |
330 | }
331 |
332 | class WPFModal : WPFElement {
333 | [StackPanel] $Stack
334 | [Window] $ModalWindow
335 |
336 | WPFModal() {
337 | $this.Stack = [StackPanel]::new()
338 | $this.SetNativeUI($this.Stack)
339 |
340 | $this.ModalWindow = [Window]::new()
341 | $this.ModalWindow.SizeToContent = 'WidthAndHeight'
342 | $this.ModalWindow.Margin = 10
343 | $this.ModalWindow.Content = [StackPanel]::new()
344 | $this.WrapProperty("Title", "Title", "ModalWindow")
345 |
346 | $this.AddNativeUIChild = {
347 | param (
348 | [WPFElement] $element
349 | )
350 | $this.ModalWindow.Content.AddChild($element.NativeUI) | Out-Null
351 | }
352 | $this.StyleComponets()
353 | }
354 |
355 | [void] Show() {
356 | $this.ModalWindow.WindowStartupLocation = "CenterOwner"
357 | $this.ModalWindow.ShowDialog()
358 | }
359 |
360 | [void] Hide() {
361 | $this.ModalWindow.Hide()
362 | }
363 |
364 | [void] StyleComponets() {
365 | $this.ModalWindow.WindowStyle = [WindowStyle]::None
366 | }
367 | }
368 |
369 | class WPFTimer : WPFElement {
370 | [System.Windows.Threading.DispatcherTimer] $Timer
371 | [Double] $Interval = 1000
372 |
373 | WPFTimer () {
374 | $label = [Label]::new()
375 | $label.Visibility = [Visibility]::Collapsed
376 | $this.SetNativeUI($label)
377 | $this.AddScriptBlockProperty("Elapsed")
378 | $this.Timer = New-Object System.Windows.Threading.DispatcherTimer
379 | Add-Member -InputObject $this.Timer -MemberType NoteProperty -Name Control -Value $this
380 | $this.Timer.Add_Tick({
381 | $this.Control.OnElapsed()
382 | #[System.Windows.Input.CommandManager]::InvalidateRequerySuggested()
383 | })
384 | }
385 |
386 | [void] OnElapsed() {
387 | Invoke-Command -ScriptBlock $this._Elapsed -ArgumentList $this
388 | }
389 |
390 | [void] Start() {
391 | $this.Timer.Interval = [TimeSpan]::FromSeconds($this.Interval / 1000)
392 | $this.Timer.Start()
393 | }
394 |
395 | [void] Stop() {
396 | $this.Timer.Stop()
397 | }
398 | }
399 |
400 | class WPFDatePicker : WPFElement {
401 |
402 | WPFDatePicker() {
403 | $this.SetNativeUI([DatePicker]::new())
404 | $this.WrapProperty("Value", "SelectedDate")
405 | $this.AddScriptBlockProperty("Change")
406 | $this.NativeUI.Add_SelectedDateChanged({ $this.Control.OnChange() })
407 | }
408 |
409 | [void] OnChange() {
410 | $this.InvokeTrappableCommand($this._Change, $this)
411 | }
412 | }
413 |
414 | class WPFTimePicker : WPFElement {
415 |
416 | WPFTimePicker() {
417 | $textBox = [TextBox]::new()
418 | $textBox.MaxLength = 5
419 | $this.SetNativeUI($textBox)
420 | Add-Member -InputObject $this -Name Value -MemberType ScriptProperty -Value {
421 | $this.GetTextTime()
422 | } -SecondValue {
423 | $this.NativeUI.Text = $args[0]
424 | }
425 | $this.AddScriptBlockProperty("Change")
426 | $this.NativeUI.Add_TextChanged({ $this.Control.OnChange() })
427 | $this.AddScriptBlockProperty("LostFocus")
428 | $this.NativeUI.Add_LostFocus({ $this.Control.OnLostFocus() })
429 | }
430 |
431 | [void] OnChange() {
432 | $this.InvokeTrappableCommand($this._Change, $this)
433 | }
434 |
435 | [void] OnLostFocus() {
436 | $this.Value = $this.GetTextTime()
437 | $this.InvokeTrappableCommand($this._LostFocus, $this)
438 | }
439 |
440 | hidden [String] GetTextTime() {
441 | [DateTime] $dateTime = [DateTime]::Today
442 | if (-not [DateTime]::TryParse("2000-01-01 " + $this.NativeUI.Text, [ref] $dateTime)) {
443 | return "00:00"
444 | } else {
445 | return $dateTime.ToShortTimeString()
446 | }
447 | }
448 |
449 | }
450 |
451 | class WPFBrowser : WPFStackPanel {
452 | [Object[]] $Data = [Object[]] @()
453 | [int] $PageRows = 10
454 | [int] $CurrentPage = 0
455 | [Boolean] $IsEditable = $true
456 | [Object] $CurrentRow
457 |
458 | #region Components Declaration
459 |
460 | hidden [WPFListColumn[]] $Columns = [WPFListColumn[]] @()
461 | hidden [WPFListColumn] $EditionColumn
462 | hidden [WPFList] $List = [WPFList]::new()
463 | hidden [WPFStackPanel] $ButtonPanel = [WPFStackPanel]::new()
464 | hidden [WPFButton] $FirstButton = [WPFButton]::new()
465 | hidden [WPFButton] $PreviousButton = [WPFButton]::new()
466 | hidden [WPFButton] $NextButton = [WPFButton]::new()
467 | hidden [WPFButton] $LastButton = [WPFButton]::new()
468 | hidden [WPFButton] $AddNewButton = [WPFButton]::new()
469 |
470 | #endregion
471 |
472 | WPFBrowser() {
473 | $this.AddScriptBlockProperty("AddNew")
474 | $this.AddScriptBlockProperty("Edit")
475 | $this.AddScriptBlockProperty("Delete")
476 | $this.AddChild($this.List)
477 | $this.AddButtons()
478 | }
479 |
480 | #region Components Creation
481 |
482 | hidden [void] AddButtons() {
483 | $this.ButtonPanel = [WPFStackPanel]::new()
484 | $this.ButtonPanel.Orientation = "Horizontal"
485 |
486 | $this.FirstButton.Action = { $this.Parent.Parent.OnMoveFirst() }
487 | $this.PreviousButton.Action = { $this.Parent.Parent.OnMovePrevious() }
488 | $this.NextButton.Action = { $this.Parent.Parent.OnMoveNext() }
489 | $this.LastButton.Action = { $this.Parent.Parent.OnMoveLast() }
490 | $this.AddNewButton.Action = { $this.Parent.Parent.OnAddNew() }
491 |
492 | $this.ButtonPanel.AddChild($this.FirstButton)
493 | $this.ButtonPanel.AddChild($this.PreviousButton)
494 | $this.ButtonPanel.AddChild($this.NextButton)
495 | $this.ButtonPanel.AddChild($this.LastButton)
496 | $this.ButtonPanel.AddChild($this.AddNewButton)
497 |
498 | $this.StyleComponents()
499 |
500 | $this.AddChild($this.ButtonPanel)
501 | }
502 |
503 | [void] AddColumn([WPFListColumn] $listColumn) {
504 | $this.Columns += $listColumn
505 | $this.List.AddColumn($listColumn)
506 | }
507 |
508 | [void] CreateList() {
509 | $this.List.Clear()
510 | $this.CreateEditable()
511 | 0..($this.PageRows - 1) | ForEach-Object {
512 | $listItem = $this.GetInitialListItem($_)
513 | $this.List.AddItem($listItem)
514 | }
515 | }
516 |
517 | hidden [ListItem] GetInitialListItem([int] $rowIndex) {
518 | $hash = $this.GetInitialHash()
519 | $listItem = [ListItem]::new()
520 | $this.Columns | ForEach-Object {
521 | $column = $_
522 | if ($column -eq $this.EditionColumn -and $this.IsEditable) {
523 | $this.AddEditionButtons($hash, $listItem, $rowIndex)
524 | } else {
525 | $this.AddCell($hash, $column.Name, $listItem, $rowIndex)
526 | }
527 | }
528 | return $listItem
529 | }
530 |
531 | hidden [Object] GetInitialHash() {
532 | $hash = @{}
533 | $this.Columns | ForEach-Object {
534 | $column = $_
535 | $hash += @{ "$($column.Name)" = "" }
536 | }
537 | return $hash
538 | }
539 |
540 | hidden [void] AddEditionButtons([Object] $hash, [ListItem] $listItem, [int] $rowIndex) {
541 | $editionPanel = [WPFStackPanel]::new()
542 | $editionPanel.Orientation = "Horizontal"
543 | $listItem.AddChild($editionPanel)
544 |
545 | $editButton = [WPFButton]::new()
546 | Add-Member -InputObject $editButton -MemberType NoteProperty -Name CurrentRow -Value $hash
547 | $editButton.Action = {
548 | $this.Parent.Parent.Parent.Parent.CurrentRow = $this.CurrentRow
549 | $this.Parent.Parent.Parent.Parent.OnEdit()
550 | }
551 | $editionPanel.AddChild($editButton)
552 |
553 | $deleteButton = [WPFButton]::new()
554 | Add-Member -InputObject $deleteButton -MemberType NoteProperty -Name CurrentRow -Value $hash
555 | $deleteButton.Action = {
556 | $this.Parent.Parent.Parent.Parent.CurrentRow = $this.CurrentRow
557 | $this.Parent.Parent.Parent.Parent.OnDelete()
558 | }
559 | $editionPanel.AddChild($deleteButton)
560 | $this.StyleEditionButtons($editButton, $deleteButton, $rowIndex)
561 | }
562 |
563 | hidden [void] AddCell([Object] $hash, [string] $columnName, [ListItem] $listItem, [int] $rowIndex) {
564 | $itemLabel = [WPFLabel]::new()
565 | $itemLabel.Caption = $hash."$columnName"
566 | $listItem.AddChild($itemLabel)
567 | $this.StyleCell($itemLabel, $rowIndex)
568 | }
569 |
570 | hidden [void] CreateEditable() {
571 | if ($this.EditionColumn -eq $null -and $this.IsEditable) {
572 | $this.CreateEditionColumn()
573 | }
574 | $this.AddNewButton.Visible = $this.IsEditable
575 | }
576 |
577 | hidden [void] CreateEditionColumn() {
578 | $this.EditionColumn = New-Object WPFListColumn -Property @{Name = "_Edition"; Title = "_"}
579 | $this.AddColumn($this.EditionColumn)
580 | }
581 |
582 | #endregion
583 |
584 | #region Data show
585 |
586 | [void] Refresh() {
587 | # Fill Rows
588 | $rowIndex = 0
589 | $selectedData = $this.GetSelectedData()
590 | $selectedData | ForEach-Object {
591 | $hash = $_
592 | $columnIndex = 0
593 | $this.Columns | Select-Object -First ($this.Columns.Count) | ForEach-Object {
594 | $column = $_
595 | if ($this.EditionColumn -ne $column) {
596 | $this.List.Children.Item($columnIndex).Children.Item($rowIndex + 1).Caption = $hash."$($column.Name)"
597 | } else {
598 | $buttons = $this.List.Children.Item($columnIndex).Children.Item($rowIndex + 1).Children
599 | $buttons.Item(0).CurrentRow = $hash
600 | $buttons.Item(1).CurrentRow = $hash
601 | $buttons.Item(0).Visible = $true
602 | $buttons.Item(1).Visible = $true
603 | }
604 | $columnIndex++
605 | }
606 | $rowIndex++
607 | }
608 | # EmptyRows
609 | for ($rowIndex = $selectedData.Count + 1; $rowIndex -le $this.PageRows; $rowIndex++) {
610 | $columnIndex = 0
611 | $this.Columns | Select-Object -First ($this.Columns.Count) | ForEach-Object {
612 | $column = $_
613 | if ($this.EditionColumn -ne $column) {
614 | $this.List.Children.Item($columnIndex).Children.Item($rowIndex).Caption = ""
615 | } else {
616 | $buttons = $this.List.Children.Item($columnIndex).Children.Item($rowIndex).Children
617 | $buttons.Item(0).Visible = $false
618 | $buttons.Item(1).Visible = $false
619 | }
620 | $columnIndex++
621 | }
622 | }
623 | }
624 |
625 | hidden [Object[]] GetSelectedData() {
626 | return $this.Data | Select-Object -Skip ($this.CurrentPage * $this.PageRows) -First $this.PageRows
627 | }
628 |
629 | hidden [int] GetLastPage() {
630 | $lastPage = [Math]::Truncate($this.Data.Count / $this.PageRows)
631 | if (($this.Data.Count % $this.PageRows) -eq 0) {
632 | $lastPage--
633 | }
634 | return $lastPage
635 | }
636 |
637 | #endregion
638 |
639 | #region Style
640 |
641 | [Media.Brush] $ShadowBrush = ([Media.Brush] "#FFF3F3F3")
642 |
643 | [Media.Brush] GetRowBackground([int] $rowIndex) {
644 | if (($rowIndex % 2) -eq 0) {
645 | return $this.ShadowBrush
646 | } else {
647 | return [Media.Brushes]::Transparent
648 | }
649 | }
650 |
651 | [void] StyleComponents() {
652 | $this.ButtonPanel.NativeUI.HorizontalAlignment = "Right"
653 |
654 | $this.FirstButton.Caption = "|<"
655 | $this.PreviousButton.Caption = "<<"
656 | $this.NextButton.Caption = ">>"
657 | $this.LastButton.Caption = ">|"
658 | $this.AddNewButton.Caption = "+"
659 |
660 | $this.FirstButton.NativeUI.Margin = 10
661 | $this.PreviousButton.NativeUI.Margin = 10
662 | $this.NextButton.NativeUI.Margin = 10
663 | $this.LastButton.NativeUI.Margin = 10
664 | $this.AddNewButton.NativeUI.Margin = 10
665 | }
666 |
667 | [void] StyleCell($cell, [int] $rowIndex) {
668 | $cell.NativeUI.Background = $this.GetRowBackground($rowIndex)
669 | }
670 |
671 | [void] StyleEditionButtons([WPFButton] $editButton, [WPFButton] $deleteButton, [int] $rowIndex) {
672 | $editButton.Caption = "/"
673 | $deleteButton.Caption = "X"
674 | $editButton.Parent.NativeUI.Background = $this.GetRowBackground($rowIndex)
675 | }
676 |
677 | #endregion
678 |
679 | #region Move Events
680 |
681 | hidden [void] OnMoveFirst() {
682 | $this.CurrentPage = 0
683 | $this.Refresh()
684 | }
685 |
686 | hidden [void] OnMovePrevious() {
687 | if ($this.CurrentPage -gt 0) {
688 | $this.CurrentPage--
689 | }
690 | $this.Refresh()
691 | }
692 |
693 | hidden [void] OnMoveNext() {
694 | if ($this.CurrentPage -lt $this.GetLastPage()) {
695 | $this.CurrentPage++
696 | }
697 | $this.Refresh()
698 | }
699 |
700 | hidden [void] OnMoveLast() {
701 | $this.CurrentPage = $this.GetLastPage()
702 | $this.Refresh()
703 | }
704 |
705 | #endregion
706 |
707 | #region CRUD Events
708 |
709 | hidden [void] OnAddNew() {
710 | $this.InvokeTrappableCommand($this._AddNew, $this)
711 | }
712 |
713 | hidden [void] OnEdit() {
714 | $this.InvokeTrappableCommand($this._Edit, $this)
715 | }
716 |
717 | hidden [void] OnDelete() {
718 | $this.InvokeTrappableCommand($this._Delete, $this)
719 | }
720 |
721 | #endregion
722 |
723 | }
724 |
725 | class WPFMenuItem : WPFElement {
726 |
727 | WPFMenuItem() {
728 | $this.SetNativeUI([MenuItem]::new())
729 | $this.WrapProperty("Caption", "Header")
730 | $this.AddScriptBlockProperty("Action")
731 | $this.NativeUI.Add_Click({ $this.Control.OnAction() })
732 | }
733 |
734 | [void] OnAction() {
735 | $this.InvokeTrappableCommand($this._Action, $this)
736 | }
737 | }
738 |
739 | class WPFDropDownMenu : WPFButton {
740 |
741 | WPFDropDownMenu() {
742 | $this.RightIcon = $true
743 | $this.Icon = [WPFIcon] @{ Kind = "chevron_down" }
744 |
745 | $this.NativeUI.ContextMenu = [ContextMenu]::new()
746 | $this.AddNativeUIChild = {
747 | param (
748 | [WPFElement] $element
749 | )
750 | $this.NativeUI.ContextMenu.Items.Add($element.NativeUI)
751 | }
752 | $this.RemoveNativeUIChild = {
753 | param (
754 | [WPFElement] $element
755 | )
756 | $this.NativeUI.ContextMenu.Items.Remove($element.NativeUI)
757 | }
758 |
759 | $this.Action = {
760 | param($this)
761 | $this.NativeUI.ContextMenu.IsOpen = -not $this.NativeUI.ContextMenu.IsOpen
762 | }
763 | }
764 |
765 | }
766 |
767 | class WPFAutoComplete : WPFTextBox {
768 |
769 | WPFAutoComplete() {
770 | $this.NativeUI.ContextMenu = [ContextMenu]::new()
771 | $this.NativeUI.ContextMenu.PlacementTarget = $this.NativeUI
772 | $this.NativeUI.ContextMenu.Placement = [System.Windows.Controls.Primitives.PlacementMode]::Bottom
773 |
774 | $this.NativeUI.Add_KeyUp({
775 | if ($_.Key -eq [Key]::Down) {
776 | $this.Control.AddItems()
777 | $this.Control.NativeUI.ContextMenu.IsOpen = $true
778 | $this.Control.NativeUI.ContextMenu.Focus()
779 | }
780 | })
781 |
782 | $this.AddScriptBlockProperty("ItemsRequested")
783 | }
784 |
785 | [void] AddItems() {
786 | $this.OnItemsRequested()
787 | }
788 |
789 | [void] OnItemsRequested() {
790 | [AutoCompleteItem[]] $items = Invoke-Command -ScriptBlock $this._ItemsRequested -ArgumentList $this | Select-Object -First 20
791 | $this.NativeUI.ContextMenu.Items.Clear()
792 | 0..($items.Count - 1) | ForEach-Object {
793 | $menuItem = [WPFMenuItem]::new()
794 | $menuItem.Caption = $items[$_].Text
795 | Add-Member -InputObject $menuItem -MemberType NoteProperty -Name AutoCompleteTextBox -Value $this
796 | Add-Member -InputObject $menuItem -MemberType NoteProperty -Name AutoCompleteId -Value $items[$_].Id
797 | $menuItem.Action = {
798 | param ($this)
799 | $this.AutoCompleteTextBox.Text = $this.AutoCompleteId
800 | $this.AutoCompleteTextBox.NativeUI.ContextMenu.IsOpen = $false
801 | }
802 | $this.NativeUI.ContextMenu.Items.Add($menuItem.NativeUI)
803 | }
804 | #$this.NativeUI.ContextMenu.MinWidth = $this.NativeUI.Width
805 | }
806 | }
807 |
808 | class WPFCard : WPFElement {
809 | hidden [GroupBox] $CardGroupBox = [GroupBox]::new()
810 | hidden [StackPanel] $HeaderStackPanel = [StackPanel]::new()
811 | hidden [TextBlock] $HeaderTextBlock = [TextBlock]::new()
812 | hidden [StackPanel] $BodyStackPanel = [StackPanel]::new()
813 | hidden $CurrentIcon = [WPFIcon]::new()
814 |
815 | WPFCard() {
816 | $this.SetNativeUI($this.CardGroupBox)
817 | $this.CardGroupBox.Header = $this.HeaderStackPanel
818 | $this.HeaderStackPanel.AddChild($this.CurrentIcon.NativeUI)
819 | $this.HeaderStackPanel.AddChild($this.HeaderTextBlock)
820 | $this.CardGroupBox.Content = $this.BodyStackPanel
821 |
822 | $this.WrapProperty("Caption", "Text", "HeaderTextBlock")
823 | Add-Member -InputObject $this -Name Icon -MemberType ScriptProperty -Value {
824 | $this.CurrentIcon
825 | } -SecondValue {
826 | $this.HeaderStackPanel.Children.Remove($this.CurrentIcon.NativeUI)
827 | $this.HeaderStackPanel.Children.Remove($this.HeaderTextBlock)
828 | $this.CurrentIcon = $args[0]
829 | $this.HeaderStackPanel.AddChild($this.CurrentIcon.NativeUI)
830 | $this.HeaderStackPanel.AddChild($this.HeaderTextBlock)
831 | $this.StyleComponents()
832 | }
833 | $this.AddNativeUIChild = {
834 | param (
835 | [WPFElement] $element
836 | )
837 | $this.BodyStackPanel.AddChild($element.NativeUI) | Out-Null
838 | }
839 | $this.StyleComponents()
840 | }
841 |
842 | [void] StyleComponents() {
843 | $this.CardGroupBox.Margin = "16"
844 | $this.HeaderStackPanel.Orientation = [Orientation]::Horizontal
845 | $this.BodyStackPanel.Orientation = [Orientation]::Vertical
846 | }
847 |
848 | }
849 |
850 | class WPFImage : WPFElement {
851 |
852 | WPFImage() {
853 | $image = [Image]::new()
854 | $this.SetNativeUI($image)
855 | $this.WrapProperty("Source", "Source")
856 | $this.WrapProperty("Width", "Width")
857 | }
858 | }
859 |
860 | class WPFTextEditor : WPFTextBox {
861 |
862 | WPFTextEditor() {
863 | #$this.NativeUI.TextWrapping = "Wrap"
864 | $this.NativeUI.AcceptsReturn = $true
865 | $this.NativeUI.VerticalScrollBarVisibility = "Visible"
866 | $this.NativeUI.HorizontalScrollBarVisibility = "Auto"
867 | Add-Member -InputObject $this -Name Height -MemberType ScriptProperty -Value {
868 | [int] $this.NativeUI.Height / 20
869 | } -SecondValue {
870 | $this.NativeUI.Height = $args[0] * 20
871 | }
872 | Add-Member -InputObject $this -Name Width -MemberType ScriptProperty -Value {
873 | [int] $this.NativeUI.Width / 20
874 | } -SecondValue {
875 | $this.NativeUI.Width = $args[0] * 20
876 | }
877 | }
878 |
879 | }
880 |
881 | class WPFExpander : WPFElement {
882 | hidden $StackPanelNativeUI = [StackPanel]::new()
883 |
884 | WPFExpander() {
885 | $this.SetNativeUI([Expander]::new())
886 | $this.WrapProperty("Caption", "Header")
887 | $this.NativeUI.Content = $this.StackPanelNativeUI
888 | $this.AddNativeUIChild = {
889 | param (
890 | [WPFElement] $element
891 | )
892 | $this.StackPanelNativeUI.AddChild($element.NativeUI) | Out-Null
893 | }
894 | }
895 | }
896 |
897 | class WPFInteger : WPFTextBox {
898 |
899 | WPFInteger() {
900 | $this.TextAlignment = [TextAlignment]::Right
901 | $this.Pattern = '^[\d]+$'
902 | $this.DefaultText = "0"
903 | $this.Text = "0"
904 | }
905 | }
906 |
907 | class WPFDouble : WPFTextBox {
908 |
909 | WPFDouble() {
910 | $this.TextAlignment = [TextAlignment]::Right
911 | $this.Pattern = '^[\d\.]+$'
912 | $this.DefaultText = "0.0"
913 | $this.Text = "0.0"
914 | }
915 | }
916 |
917 | class WPFComboBoxItem : WPFElement {
918 |
919 | WPFComboBoxItem() {
920 | $this.SetNativeUI([ComboBoxItem]::new())
921 | $this.WrapProperty("Id" , "Tag")
922 | $this.WrapProperty("Caption", "Content")
923 | }
924 | }
925 |
926 | class WPFComboBox : WPFElement {
927 |
928 | WPFComboBox() {
929 | $this.SetNativeUI([ComboBox]::new())
930 | Add-Member -InputObject $this -Name Text -MemberType ScriptProperty -Value {
931 | $this.NativeUI.SelectedItem.Tag
932 | } -SecondValue {
933 | $id = $Args[0]
934 | $selectedItem = $this.NativeUI.Items | Where-Object { $_.Tag -eq $id }
935 | if ($selectedItem -ne $null) {
936 | $this.NativeUI.SelectedItem = $selectedItem
937 | }
938 | }
939 | $this.AddScriptBlockProperty("Change")
940 | $this.NativeUI.Add_SelectionChanged({ $this.Control.OnChange() })
941 | $this.AddNativeUIChild = {
942 | param (
943 | [WPFElement] $element
944 | )
945 | $this.NativeUI.Items.Add($element.NativeUI)
946 | }
947 | }
948 |
949 | [void] OnChange() {
950 | $this.InvokeTrappableCommand($this._Change, $this)
951 | }
952 |
953 | }
954 |
955 | class WPFFileUpload : WPFLabel {
956 | }
--------------------------------------------------------------------------------
/sign-form.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/code-numericoverflow/UIfied/c8f7ca83c538a7e20970eaf0c38451bc2767a450/sign-form.png
--------------------------------------------------------------------------------