LIMITED WARRANTY NO WARRANTIES. Larabie Fonts expressly disclaims any warranty for the SOFTWARE PRODUCT. The SOFTWARE PRODUCT and any related documentation is provided "as is" without warranty of any kind, either express or implied, including, without limitation, the implied warranties or merchantability, fitness for a particular purpose, or non-infringement. The entire risk arising out of use or performance of the SOFTWARE PRODUCT remains with you.
NO LIABILITY FOR CONSEQUENTIAL DAMAGES. In no event shall Larabie Fonts be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or any other pecuniary loss) arising out of the use of or inability to use this product, even if Larabie Fonts has been advised of the possibility of such damages.
3. MISCELLANEOUS
Should you have any questions concerning this document, or if you desire to contact Larabie Fonts for any reason, please email www.larabiefonts.com/email.html.
+
diff --git a/ReCap.CommonUI/Res/UI/Test.png b/ReCap.CommonUI/Res/UI/Test.png
new file mode 100644
index 0000000..6d95b8c
Binary files /dev/null and b/ReCap.CommonUI/Res/UI/Test.png differ
diff --git a/ReCap.CommonUI/Res/UI/TopTabs/SelectedBackground.png b/ReCap.CommonUI/Res/UI/TopTabs/SelectedBackground.png
new file mode 100644
index 0000000..c0f5c79
Binary files /dev/null and b/ReCap.CommonUI/Res/UI/TopTabs/SelectedBackground.png differ
diff --git a/ReCap.CommonUI/Res/UI/TopTabs/TabRow.png b/ReCap.CommonUI/Res/UI/TopTabs/TabRow.png
new file mode 100644
index 0000000..5e44c0d
Binary files /dev/null and b/ReCap.CommonUI/Res/UI/TopTabs/TabRow.png differ
diff --git a/ReCap.CommonUI/Styles/Controls.axaml b/ReCap.CommonUI/Styles/Controls.axaml
new file mode 100755
index 0000000..2595223
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Controls.axaml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ReCap.CommonUI/Styles/Controls/Button_RepeatButton_ToggleButton.axaml b/ReCap.CommonUI/Styles/Controls/Button_RepeatButton_ToggleButton.axaml
new file mode 100644
index 0000000..209f47a
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Controls/Button_RepeatButton_ToggleButton.axaml
@@ -0,0 +1,118 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Controls/CaptionButtons.axaml b/ReCap.CommonUI/Styles/Controls/CaptionButtons.axaml
new file mode 100755
index 0000000..7ec64f1
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Controls/CaptionButtons.axaml
@@ -0,0 +1,261 @@
+
+
+ M 0 0 L 3 0 L 5 2 L 7 0 L 10 0
+ L 10 0.5 L 7 4.5 L 10 8.5 L 10 9
+ L 7 9 L 5 7 L 3 9 L 0 9
+ L 0 8.5 L 3 4.5 L 0 0.5 Z
+
+
+ Maximized
+
+
+ Maximized
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Controls/Closeable.axaml b/ReCap.CommonUI/Styles/Controls/Closeable.axaml
new file mode 100644
index 0000000..53e1003
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Controls/Closeable.axaml
@@ -0,0 +1,194 @@
+
+ 0:0:0.375
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Controls/GroupBox.axaml b/ReCap.CommonUI/Styles/Controls/GroupBox.axaml
new file mode 100644
index 0000000..403e5a7
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Controls/GroupBox.axaml
@@ -0,0 +1,86 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Controls/ListBox.axaml b/ReCap.CommonUI/Styles/Controls/ListBox.axaml
new file mode 100644
index 0000000..fcb294b
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Controls/ListBox.axaml
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Controls/ListBoxItem.axaml b/ReCap.CommonUI/Styles/Controls/ListBoxItem.axaml
new file mode 100644
index 0000000..3b1ab74
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Controls/ListBoxItem.axaml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Controls/OverlayPopupHost.axaml b/ReCap.CommonUI/Styles/Controls/OverlayPopupHost.axaml
new file mode 100755
index 0000000..2dc4cd9
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Controls/OverlayPopupHost.axaml
@@ -0,0 +1,17 @@
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Controls/ScrollBar.axaml b/ReCap.CommonUI/Styles/Controls/ScrollBar.axaml
new file mode 100644
index 0000000..791f756
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Controls/ScrollBar.axaml
@@ -0,0 +1,525 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Controls/ScrollViewer.axaml b/ReCap.CommonUI/Styles/Controls/ScrollViewer.axaml
new file mode 100755
index 0000000..6ab37d9
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Controls/ScrollViewer.axaml
@@ -0,0 +1,88 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Controls/TabControl.axaml b/ReCap.CommonUI/Styles/Controls/TabControl.axaml
new file mode 100644
index 0000000..83fa79f
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Controls/TabControl.axaml
@@ -0,0 +1,226 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -->
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Controls/TabItem_TabStripItem.axaml b/ReCap.CommonUI/Styles/Controls/TabItem_TabStripItem.axaml
new file mode 100644
index 0000000..e5b9e9a
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Controls/TabItem_TabStripItem.axaml
@@ -0,0 +1,139 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Controls/TextBox.axaml b/ReCap.CommonUI/Styles/Controls/TextBox.axaml
new file mode 100644
index 0000000..a7a7f26
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Controls/TextBox.axaml
@@ -0,0 +1,231 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Controls/TitleBar.axaml b/ReCap.CommonUI/Styles/Controls/TitleBar.axaml
new file mode 100755
index 0000000..4e37956
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Controls/TitleBar.axaml
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ReCap.CommonUI/Styles/Controls/TitleBarUnderlay.axaml b/ReCap.CommonUI/Styles/Controls/TitleBarUnderlay.axaml
new file mode 100755
index 0000000..b9db14f
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Controls/TitleBarUnderlay.axaml
@@ -0,0 +1,67 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ReCap.CommonUI/Styles/Controls/Window.axaml b/ReCap.CommonUI/Styles/Controls/Window.axaml
new file mode 100755
index 0000000..5f09e36
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Controls/Window.axaml
@@ -0,0 +1,198 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Resources.axaml b/ReCap.CommonUI/Styles/Resources.axaml
new file mode 100755
index 0000000..39dd088
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Resources.axaml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Resources/Button.axaml b/ReCap.CommonUI/Styles/Resources/Button.axaml
new file mode 100644
index 0000000..5ce8510
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Resources/Button.axaml
@@ -0,0 +1,22 @@
+
+ #40A7CBE2
+ #A3FFFFFF
+ #40FFFFFF
+
+
+ #C0FFFFFF
+ #7FFFFFFF
+
+ #C0809CAD
+ #7FA7CBE2
+
+
+ #40C9C9C9
+ #51FFFFFF
+ #20FFFFFF
+
+
+ #C0AAAAAA
+ #7FE0E0E0
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Resources/CaptionButtons.axaml b/ReCap.CommonUI/Styles/Resources/CaptionButtons.axaml
new file mode 100755
index 0000000..0a421e7
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Resources/CaptionButtons.axaml
@@ -0,0 +1,72 @@
+
+
+
+
+
+ #FFDECCCC
+ #FFDE0000
+
+
+
+
+
+
+ #FFDDD9D9
+ #FF875A5A
+
+
+
+
+
+
+
+ #FFFFCCCC
+ #FFFFFFFF
+
+
+
+
+
+
+ #FFA00000
+ #FF120000
+
+
+ #FF2D2D2D
+ #FFD1D1D1
+ #FF898989
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Resources/Global.axaml b/ReCap.CommonUI/Styles/Resources/Global.axaml
new file mode 100755
index 0000000..2d0a033
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Resources/Global.axaml
@@ -0,0 +1,33 @@
+
+ Normal
+ Normal
+ Normal
+
+
+
+ 12
+ 30
+ 22
+ 15
+
+
+
+ #FFFFFFFF
+
+
+ #E0FFFFFF
+
+
+ #96FFFFFF
+
+
+
+ avares://ReCap.CommonUI/Res/UI/Font/Header#Pirulen
+ avares://ReCap.CommonUI/Res/UI/Font/Body#RobotoCondensed
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Resources/GroupBox.axaml b/ReCap.CommonUI/Styles/Resources/GroupBox.axaml
new file mode 100644
index 0000000..3316188
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Resources/GroupBox.axaml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Resources/ListBoxItem.axaml b/ReCap.CommonUI/Styles/Resources/ListBoxItem.axaml
new file mode 100644
index 0000000..ac00b31
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Resources/ListBoxItem.axaml
@@ -0,0 +1,15 @@
+
+ #FF0A121D
+ #9038566B
+ #40FFFFFF
+
+ #FF558CBA
+ #9092EDFF
+ #80FFFFFF
+
+ #C0FFFFFF
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Resources/ScrollBar.axaml b/ReCap.CommonUI/Styles/Resources/ScrollBar.axaml
new file mode 100644
index 0000000..b2e6fc1
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Resources/ScrollBar.axaml
@@ -0,0 +1,98 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #FF378FB6
+ #FF5BDEF3
+
+
+
+
+
+ #FF67B4E1
+
+
+ #FF72BAD9
+ #FF93F5FF
+
+
+
+
+ #FF9BD7F6
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ M 0 5 L 0 4 L 4 0 L 8 4 L 8 5 L 7 5 L 4 2 L 1 5 Z
+ M 5 0 L 4 0 L 0 4 L 4 8 L 5 8 L 5 7 L 2 4 L 5 1 Z
+
+ #FF6CC0EA
+ #FFA3DEFF
+
+ 18
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Resources/SidePane.axaml b/ReCap.CommonUI/Styles/Resources/SidePane.axaml
new file mode 100644
index 0000000..95c3295
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Resources/SidePane.axaml
@@ -0,0 +1,37 @@
+
+
+ #59B7CFDA
+ #96FFFFFF
+ #39E1E2E2
+
+
+ #FF000000
+ #80000000
+
+
+
+
+
+
+ 6
+ 18
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Resources/TabControl.axaml b/ReCap.CommonUI/Styles/Resources/TabControl.axaml
new file mode 100644
index 0000000..eaec382
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Resources/TabControl.axaml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+ #53CACACA
+
+
+
+
+
+ #38DADADA
+
+
+
+
+
+
+ #B0BBD7E1
+
+
+
+
+
+ #78C3E5F1
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Resources/TextBox.axaml b/ReCap.CommonUI/Styles/Resources/TextBox.axaml
new file mode 100644
index 0000000..72c1fc0
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Resources/TextBox.axaml
@@ -0,0 +1,36 @@
+
+ 0,0,0,4
+ M 11.416016,10 20,1.4160156 18.583984,0 10,8.5839846 1.4160156,0 0,1.4160156 8.5839844,10 0,18.583985 1.4160156,20 10,11.416015 18.583984,20 20,18.583985 Z
+ m10.051 7.0032c2.215 0 4.0105 1.7901 4.0105 3.9984s-1.7956 3.9984-4.0105 3.9984c-2.215 0-4.0105-1.7901-4.0105-3.9984s1.7956-3.9984 4.0105-3.9984zm0 1.4994c-1.3844 0-2.5066 1.1188-2.5066 2.499s1.1222 2.499 2.5066 2.499 2.5066-1.1188 2.5066-2.499-1.1222-2.499-2.5066-2.499zm0-5.0026c4.6257 0 8.6188 3.1487 9.7267 7.5613 0.10085 0.40165-0.14399 0.80877-0.54686 0.90931-0.40288 0.10054-0.81122-0.14355-0.91208-0.54521-0.94136-3.7492-4.3361-6.4261-8.2678-6.4261-3.9334 0-7.3292 2.6792-8.2689 6.4306-0.10063 0.40171-0.50884 0.64603-0.91177 0.54571s-0.648-0.5073-0.54737-0.90901c1.106-4.4152 5.1003-7.5667 9.728-7.5667z
+ m0.21967 0.21965c-0.26627 0.26627-0.29047 0.68293-0.07262 0.97654l0.07262 0.08412 4.0346 4.0346c-1.922 1.3495-3.3585 3.365-3.9554 5.7495-0.10058 0.4018 0.14362 0.8091 0.54543 0.9097 0.40182 0.1005 0.80909-0.1436 0.90968-0.5455 0.52947-2.1151 1.8371-3.8891 3.5802-5.0341l1.8096 1.8098c-0.70751 0.7215-1.1438 1.71-1.1438 2.8003 0 2.2092 1.7909 4 4 4 1.0904 0 2.0788-0.4363 2.8004-1.1438l5.9193 5.9195c0.2929 0.2929 0.7677 0.2929 1.0606 0 0.2663-0.2662 0.2905-0.6829 0.0726-0.9765l-0.0726-0.0841-6.1135-6.1142 0.0012-0.0015-1.2001-1.1979-2.8699-2.8693 2e-3 -8e-4 -2.8812-2.8782 0.0012-0.0018-1.1333-1.1305-4.3064-4.3058c-0.29289-0.29289-0.76777-0.29289-1.0607 0zm7.9844 9.0458 3.5351 3.5351c-0.45 0.4358-1.0633 0.704-1.7392 0.704-1.3807 0-2.5-1.1193-2.5-2.5 0-0.6759 0.26824-1.2892 0.7041-1.7391zm1.7959-5.7655c-1.0003 0-1.9709 0.14807-2.8889 0.425l1.237 1.2362c0.5358-0.10587 1.0883-0.16119 1.6519-0.16119 3.9231 0 7.3099 2.6803 8.2471 6.4332 0.1004 0.4018 0.5075 0.6462 0.9094 0.5459 0.4019-0.1004 0.6463-0.5075 0.5459-0.9094-1.103-4.417-5.0869-7.5697-9.7024-7.5697zm0.1947 3.5093 3.8013 3.8007c-0.1018-2.0569-1.7488-3.7024-3.8013-3.8007z
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #E0151819
+ #E02F3031
+ #FF99999A
+ #80F5F5F5
+
+ #E0252829
+ #E03F4041
+ #FFA9A9AA
+
+ #E065696B
+ #FFD3D4D4
+ #FFFFFFFF
+ #FF0A0A0A
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Resources/TopTabStrip.axaml b/ReCap.CommonUI/Styles/Resources/TopTabStrip.axaml
new file mode 100644
index 0000000..658451f
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Resources/TopTabStrip.axaml
@@ -0,0 +1,12 @@
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Resources/Window.axaml b/ReCap.CommonUI/Styles/Resources/Window.axaml
new file mode 100755
index 0000000..d2b8eb2
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Resources/Window.axaml
@@ -0,0 +1,121 @@
+
+ #FFC0C0C0
+
+ #F7111213
+ #7FFFFFFF
+ #40FFFFFF
+ #00FFFFFF
+
+
+
+
+
+
+
+
+
+ #BBB7CFDA
+ #7C93A5AD
+
+
+
+
+
+ #BBD8D8D8
+ #7CAAAAAA
+
+
+
+
+
+
+ #A8474F53
+
+
+
+
+
+ #A84D4D4D
+
+
+
+
+
+
+ #40FFFFFF
+ #80FFFFFF
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #BDA4B2B9
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ #9D0D0F12
+ #6F5D5F62
+
+ #FF25272A
+ #FF3D3F42
+ #FF515356
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Supplementary.axaml b/ReCap.CommonUI/Styles/Supplementary.axaml
new file mode 100755
index 0000000..dd7a0ec
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Supplementary.axaml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ReCap.CommonUI/Styles/Supplementary/ButtonPanels.axaml b/ReCap.CommonUI/Styles/Supplementary/ButtonPanels.axaml
new file mode 100644
index 0000000..13cb778
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Supplementary/ButtonPanels.axaml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Supplementary/DialogParts.axaml b/ReCap.CommonUI/Styles/Supplementary/DialogParts.axaml
new file mode 100644
index 0000000..adec0ff
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Supplementary/DialogParts.axaml
@@ -0,0 +1,149 @@
+
+ #D8000000
+
+
+ #E0000000
+ #7FFFFFFF
+ #20FFFFFF
+
+
+
+
+ #DDD5E1E4
+ #DDD5E1E4
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Supplementary/HelixTabItem.axaml b/ReCap.CommonUI/Styles/Supplementary/HelixTabItem.axaml
new file mode 100755
index 0000000..cdd60f8
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Supplementary/HelixTabItem.axaml
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Supplementary/HelixTabs.axaml b/ReCap.CommonUI/Styles/Supplementary/HelixTabs.axaml
new file mode 100755
index 0000000..2acbdde
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Supplementary/HelixTabs.axaml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Supplementary/HelixWindow.axaml b/ReCap.CommonUI/Styles/Supplementary/HelixWindow.axaml
new file mode 100755
index 0000000..c41ec38
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Supplementary/HelixWindow.axaml
@@ -0,0 +1,110 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ -->
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Supplementary/HexagonRingProgressBar.axaml b/ReCap.CommonUI/Styles/Supplementary/HexagonRingProgressBar.axaml
new file mode 100755
index 0000000..4325d7c
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Supplementary/HexagonRingProgressBar.axaml
@@ -0,0 +1,277 @@
+
+
+
+
+
+ 0:0:2.4
+ 0:0:0.4
+
+
+
+
+
+ #FF91A2AA
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Supplementary/InventoryTabItem.axaml b/ReCap.CommonUI/Styles/Supplementary/InventoryTabItem.axaml
new file mode 100755
index 0000000..2eb306d
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Supplementary/InventoryTabItem.axaml
@@ -0,0 +1,125 @@
+
+
+
+
+
+
+
+
+
+ #80000000
+ #B6A2A7AE
+
+ #FFFFFFFF
+
+
+
+
+
+
+ #B4A4A9B0
+ #80FFFFFF
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Supplementary/InventoryTabs.axaml b/ReCap.CommonUI/Styles/Supplementary/InventoryTabs.axaml
new file mode 100755
index 0000000..1166459
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Supplementary/InventoryTabs.axaml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Supplementary/RowBelowTabs.axaml b/ReCap.CommonUI/Styles/Supplementary/RowBelowTabs.axaml
new file mode 100755
index 0000000..0d8ce9a
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Supplementary/RowBelowTabs.axaml
@@ -0,0 +1,95 @@
+
+ #80B7CFDA
+
+
+
+
+
+
+
+
+
+ #80FFFFFF
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Supplementary/SidePane.axaml b/ReCap.CommonUI/Styles/Supplementary/SidePane.axaml
new file mode 100755
index 0000000..4ece49b
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Supplementary/SidePane.axaml
@@ -0,0 +1,206 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Styles/Supplementary/TextBlockExtras.axaml b/ReCap.CommonUI/Styles/Supplementary/TextBlockExtras.axaml
new file mode 100755
index 0000000..3ec1c6d
--- /dev/null
+++ b/ReCap.CommonUI/Styles/Supplementary/TextBlockExtras.axaml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ReCap.CommonUI/Util/Extensions.cs b/ReCap.CommonUI/Util/Extensions.cs
new file mode 100755
index 0000000..78880ba
--- /dev/null
+++ b/ReCap.CommonUI/Util/Extensions.cs
@@ -0,0 +1,83 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.Presenters;
+using Avalonia.Input;
+
+namespace ReCap.CommonUI
+{
+ public static partial class Extensions
+ {
+ public static bool TryGetHWnd(this Window win, out IntPtr hWnd)
+ {
+ hWnd = IntPtr.Zero;
+ if (win == null)
+ return false;
+
+ var platHandle = win.TryGetPlatformHandle();
+ if (platHandle == null)
+ return false;
+
+ IntPtr? hWndMaybe = platHandle.Handle;
+ if (!hWndMaybe.HasValue)
+ return false;
+
+ hWnd = hWndMaybe.Value;
+ return true;
+ }
+
+ public static void MakeControlTypeNonInteractive()
+ where T : AvaloniaObject
+ {
+ InputElement.FocusableProperty.OverrideDefaultValue(false);
+ InputElement.IsTabStopProperty.OverrideDefaultValue(false);
+ ContentPresenter.RecognizesAccessKeyProperty.OverrideDefaultValue(false);
+ }
+
+ public static IEnumerable AppendRange(this IEnumerable appendTo, IEnumerable appendFrom)
+ => appendTo.AppendRange(appendFrom.ToArray());
+
+ public static IEnumerable AppendRange(this IEnumerable appendTo, params T[] appendFrom)
+ {
+ var ret = appendTo.ToList();
+ ret.AddRange(appendFrom);
+ return ret;
+ }
+
+
+
+
+ public static bool TryGetOldValue(this AvaloniaPropertyChangedEventArgs e, out T oldValue)
+ {
+ if (e == null)
+ {
+ oldValue = default;
+ return false;
+ }
+
+ oldValue = e.GetOldValue();
+ return true;
+ }
+
+ public static bool TryGetNewValue(this AvaloniaPropertyChangedEventArgs e, out T newValue)
+ {
+ if (e == null)
+ {
+ newValue = default;
+ return false;
+ }
+
+ newValue = e.GetNewValue();
+ return true;
+ }
+
+ public static bool TryGetOldAndNewValue(this AvaloniaPropertyChangedEventArgs e, out T oldValue, out T newValue)
+ {
+ bool oldRet = e.TryGetOldValue(out oldValue);
+ bool newRet = e.TryGetNewValue(out newValue);
+ return oldRet && newRet;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ReCap.CommonUI/Util/OSInfo.cs b/ReCap.CommonUI/Util/OSInfo.cs
new file mode 100755
index 0000000..269b798
--- /dev/null
+++ b/ReCap.CommonUI/Util/OSInfo.cs
@@ -0,0 +1,59 @@
+using System;
+using System.Runtime.InteropServices;
+
+namespace ReCap.CommonUI
+{
+ public static class OSInfo
+ {
+ public static readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
+ public static readonly bool IsLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
+ public static readonly bool IsMacOS = RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
+
+ public static readonly Version Version;
+ public static readonly bool IsVersionDefinitelyAccurate;
+ static OSInfo()
+ {
+ if (IsWindows)
+ {
+ if (TryGetWindowsVersion(out Version))
+ {
+ IsVersionDefinitelyAccurate = true;
+ }
+ else
+ {
+ Version = Environment.OSVersion.Version;
+ IsVersionDefinitelyAccurate = false;
+ }
+ }
+ else
+ {
+ Version = Environment.OSVersion.Version;
+ IsVersionDefinitelyAccurate = true;
+ }
+ }
+
+
+
+ static bool TryGetWindowsVersion(out Version osVersion)
+ {
+ osVersion = default;
+ try
+ {
+ if (!SafeRtlGetVersion(out WinUnmanagedMethods.RTL_OSVERSIONINFOEX osVersionInfoEx))
+ return false;
+
+ osVersion = new Version((int)osVersionInfoEx.dwMajorVersion, (int)osVersionInfoEx.dwMinorVersion, (int)osVersionInfoEx.dwBuildNumber);
+ return true;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+ static bool SafeRtlGetVersion(out WinUnmanagedMethods.RTL_OSVERSIONINFOEX osVersionInfoEx)
+ {
+ osVersionInfoEx = new WinUnmanagedMethods.RTL_OSVERSIONINFOEX();
+ return WinUnmanagedMethods.RtlGetVersion(ref osVersionInfoEx) == 0;
+ }
+ }
+}
diff --git a/ReCap.CommonUI/Util/ReflectionHelper.cs b/ReCap.CommonUI/Util/ReflectionHelper.cs
new file mode 100644
index 0000000..94f9329
--- /dev/null
+++ b/ReCap.CommonUI/Util/ReflectionHelper.cs
@@ -0,0 +1,143 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using ReCap.CommonUI.Reflection;
+
+namespace ReCap.CommonUI
+{
+ public static class ReflectionHelper
+ {
+ const BindingFlags _FLAGS_ALL = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
+
+ static bool TryGetMethodInternal(Type ownerType, string name, BindingFlags flags, out MethodInfo methodInfo)
+ {
+ methodInfo = null;
+
+ var methods = ownerType.GetMethods(flags);
+ foreach (MethodInfo mInfo in methods)
+ {
+ if (methodInfo.Name.Contains(name))
+ {
+ methodInfo = mInfo;
+ break;
+ }
+ }
+
+ return methodInfo != null;
+ }
+ static MethodInfo GetMethodInternal(Type ownerType, string name, BindingFlags flags)
+ {
+ if (!TryGetMethodInternal(ownerType, name, flags, out MethodInfo info))
+ throw new NullReferenceException($"Type '{ownerType.Name}' has no '{name}' method!");
+
+ return info;
+ }
+
+ public static MethodWrapper GetUntypedMethod(Type ownerType, string name, BindingFlags flags = _FLAGS_ALL)
+ {
+ var methodInfo = GetMethodInternal(ownerType, name, flags);
+ return new MethodWrapper(methodInfo);
+ }
+
+ public static OMethodWrapper GetOwnerTypedMethod(string name, BindingFlags flags = _FLAGS_ALL)
+ {
+ var methodInfo = GetMethodInternal(typeof(TOwner), name, flags);
+ //if (methodInfo.ReturnType == typeof(void))
+
+ return new OMethodWrapper(methodInfo);
+ }
+
+ public static OPMethodWrapper GetOwnerTypedMethodWithTypedParams(string name, BindingFlags flags = _FLAGS_ALL)
+ {
+ var methodInfo = GetMethodInternal(typeof(TOwner), name, flags);
+ return new OPMethodWrapper(methodInfo);
+ }
+
+ public static OPMethodWrapper GetOwnerTypedMethodWithTypedParams(string name, BindingFlags flags = _FLAGS_ALL)
+ {
+ var methodInfo = GetMethodInternal(typeof(TOwner), name, flags);
+ return new OPMethodWrapper(methodInfo);
+ }
+
+ public static OPMethodWrapper GetOwnerTypedMethodWithTypedParams(string name, BindingFlags flags = _FLAGS_ALL)
+ {
+ var methodInfo = GetMethodInternal(typeof(TOwner), name, flags);
+ return new OPMethodWrapper(methodInfo);
+ }
+
+ public static OPMethodWrapper GetOwnerTypedMethodWithTypedParams(string name, BindingFlags flags = _FLAGS_ALL)
+ {
+ var methodInfo = GetMethodInternal(typeof(TOwner), name, flags);
+ return new OPMethodWrapper(methodInfo);
+ }
+
+
+ public static bool IsAssignableTo(this Type self, Type c)
+ => c.IsAssignableFrom(self);
+
+ public static bool IsParameterValid(this ParameterInfo info)
+ => IsParameterValid(info, typeof(TParam));
+ public static bool IsParameterValid(this ParameterInfo info, Type expectedType)
+ => info.ParameterType.IsAssignableTo(expectedType);
+
+ public static bool AreParametersValid(this MethodInfo methodInfo, params Type[] expectedTypes)
+ => AreParametersValid(methodInfo.GetParameters(), expectedTypes);
+ public static bool AreParametersValid(IEnumerable methodParams, params Type[] expectedTypes)
+ => AreParametersValid(methodParams.ToArray(), expectedTypes);
+ public static bool AreParametersValid(ParameterInfo[] methodParams, params Type[] expectedTypes)
+ {
+ int actualParamCount = methodParams.Length;
+ int expectedParamCount = expectedTypes.Length;
+ if (expectedParamCount > actualParamCount)
+ {
+ throw new IndexOutOfRangeException($"Expected {expectedParamCount} parameters, but matched method has only {actualParamCount} parameters!");
+ }
+ else if (expectedParamCount < actualParamCount)
+ {
+ throw new IndexOutOfRangeException($"Matched method has {actualParamCount} parameters, but only {expectedParamCount} parameters were expected!");
+ }
+
+
+ for (int i = 0; i < actualParamCount; i++)
+ {
+ var paramInfo = methodParams[i];
+ var expectedType = expectedTypes[i];
+ if (!paramInfo.IsParameterValid(expectedType))
+ throw new InvalidCastException($"Parameter at [{i}] is of type '{paramInfo.ParameterType}', which is incompatible with expected type '{expectedType}'!");
+ }
+
+ return true;
+ }
+ public static bool AreParametersValid(this MethodInfo methodInfo, out Exception exception, params Type[] expectedTypes)
+ => AreParametersValid(methodInfo.GetParameters(), out exception, expectedTypes);
+ public static bool AreParametersValid(IEnumerable methodParams, out Exception exception, params Type[] expectedTypes)
+ => AreParametersValid(methodParams.ToArray(), out exception, expectedTypes);
+ public static bool AreParametersValid(ParameterInfo[] methodParams, out Exception exception, params Type[] expectedTypes)
+ {
+ exception = null;
+ try
+ {
+ return AreParametersValid(methodParams, expectedTypes);
+ }
+ catch (Exception ex)
+ {
+ exception = ex;
+ return false;
+ }
+ }
+
+ /*
+ public static ORMethodWrapper GetOwnerAndReturnTypedMethod(string name, BindingFlags flags = _FLAGS_ALL)
+ {
+ var methodInfo = GetMethodInternal(typeof(TOwner), name, flags);
+ var returnType = methodInfo.ReturnType;
+ if (!returnType.IsAssignableTo(typeof(TRet))) //typeof(void)
+ throw new InvalidCastException($"Method found has return type '{returnType}', which is incompatible with requested return type '{typeof(TRet)}'");
+
+ return new ORMethodWrapper(methodInfo);
+ }
+ */
+ }
+}
\ No newline at end of file
diff --git a/ReCap.CommonUI/Util/ReflectionWrappers.cs b/ReCap.CommonUI/Util/ReflectionWrappers.cs
new file mode 100644
index 0000000..49ed2bf
--- /dev/null
+++ b/ReCap.CommonUI/Util/ReflectionWrappers.cs
@@ -0,0 +1,160 @@
+using System;
+using System.Reflection;
+
+namespace ReCap.CommonUI.Reflection
+{
+ public class MethodWrapper
+ {
+ protected readonly MethodInfo _methodInfo;
+ internal MethodWrapper(MethodInfo methodInfo)
+ {
+ _methodInfo = methodInfo;
+ }
+ protected MethodWrapper()
+ : this(null)
+ => throw new Exception();
+
+ protected object InvokeInternal(object instance, params object[] parameters)
+ => _methodInfo.Invoke(instance, parameters);
+
+ public object StaticCall(params object[] parameters)
+ => InvokeInternal(default, parameters);
+
+ public object InstanceCall(object instance, params object[] parameters)
+ => InvokeInternal(instance, parameters);
+
+ protected static object[] ToParamArray(params object[] objects)
+ => objects;
+ }
+ public class OMethodWrapper
+ : MethodWrapper
+ {
+ internal OMethodWrapper(MethodInfo methodInfo)
+ : base(methodInfo)
+ {}
+ public object InstanceCall(TOwner instance, params object[] parameters)
+ => InvokeInternal(instance, parameters);
+
+
+ protected static TRet ValidateReturn(object value)
+ => (value is TRet ret)
+ ? ret
+ : default
+ ;
+
+ public TRet StaticCall(params object[] parameters)
+ => ValidateReturn(InvokeInternal(default, parameters));
+ public TRet InstanceCall(TOwner instance, params object[] parameters)
+ => ValidateReturn(_methodInfo.Invoke(instance, parameters));
+ /*
+ public TRet InvokeStatic(params object[] parameters)
+ => InvokeInstance(default, parameters);
+
+ public TRet InvokeInstance(TOwner instance, params object[] parameters)
+ => (_methodInfo.Invoke(instance, parameters) is TRet ret)
+ ? ret
+ : default
+ ;
+ */
+ }
+
+ public class OPMethodWrapper
+ : OMethodWrapper
+ {
+ internal OPMethodWrapper(MethodInfo methodInfo)
+ : base(methodInfo)
+ {
+ methodInfo.AreParametersValid(typeof(TParam1));
+ }
+
+ object CallInternal(TOwner instance, TParam1 p1)
+ => InstanceCall(instance, p1);
+ TRet CallInternalT(TOwner instance, TParam1 p1)
+ => ValidateReturn(CallInternal(instance, p1));
+
+ public object StaticCall(TParam1 p1)
+ => CallInternal(default, p1);
+ public object InstanceCall(TOwner instance, TParam1 p1)
+ => CallInternal(instance, p1);
+
+ public TRet StaticCall(TParam1 p1)
+ => CallInternalT(default, p1);
+ public TRet InstanceCall(TOwner instance, TParam1 p1)
+ => CallInternalT(instance, p1);
+ }
+
+ public class OPMethodWrapper
+ : OMethodWrapper
+ {
+ internal OPMethodWrapper(MethodInfo methodInfo)
+ : base(methodInfo)
+ {
+ methodInfo.AreParametersValid(typeof(TParam1), typeof(TParam2));
+ }
+
+ object CallInternal(TOwner instance, TParam1 p1, TParam2 p2)
+ => InstanceCall(instance, p1, p2);
+ TRet CallInternalT(TOwner instance, TParam1 p1, TParam2 p2)
+ => ValidateReturn(CallInternal(instance, p1, p2));
+
+ public object StaticCall(TParam1 p1, TParam2 p2)
+ => CallInternal(default, p1, p2);
+ public object InstanceCall(TOwner instance, TParam1 p1, TParam2 p2)
+ => CallInternal(instance, p1, p2);
+
+ public TRet StaticCall(TParam1 p1, TParam2 p2)
+ => CallInternalT(default, p1, p2);
+ public TRet InstanceCall(TOwner instance, TParam1 p1, TParam2 p2)
+ => CallInternalT(instance, p1, p2);
+ }
+
+ public class OPMethodWrapper
+ : OMethodWrapper
+ {
+ internal OPMethodWrapper(MethodInfo methodInfo)
+ : base(methodInfo)
+ {
+ methodInfo.AreParametersValid(typeof(TParam1), typeof(TParam2), typeof(TParam3));
+ }
+
+ object CallInternal(TOwner instance, TParam1 p1, TParam2 p2, TParam3 p3)
+ => InstanceCall(instance, p1, p2, p3);
+ TRet CallInternalT(TOwner instance, TParam1 p1, TParam2 p2, TParam3 p3)
+ => ValidateReturn(CallInternal(instance, p1, p2, p3));
+
+ public object StaticCall(TParam1 p1, TParam2 p2, TParam3 p3)
+ => CallInternal(default, p1, p2, p3);
+ public object InstanceCall(TOwner instance, TParam1 p1, TParam2 p2, TParam3 p3)
+ => CallInternal(instance, p1, p2, p3);
+
+ public TRet StaticCall(TParam1 p1, TParam2 p2, TParam3 p3)
+ => CallInternalT(default, p1, p2, p3);
+ public TRet InstanceCall(TOwner instance, TParam1 p1, TParam2 p2, TParam3 p3)
+ => CallInternalT(instance, p1, p2, p3);
+ }
+
+ public class OPMethodWrapper
+ : OMethodWrapper
+ {
+ internal OPMethodWrapper(MethodInfo methodInfo)
+ : base(methodInfo)
+ {
+ methodInfo.AreParametersValid(typeof(TParam1), typeof(TParam2), typeof(TParam3), typeof(TParam4));
+ }
+
+ object CallInternal(TOwner instance, TParam1 p1, TParam2 p2, TParam3 p3, TParam4 p4)
+ => InstanceCall(instance, p1, p2, p3, p4);
+ TRet CallInternalT(TOwner instance, TParam1 p1, TParam2 p2, TParam3 p3, TParam4 p4)
+ => ValidateReturn(CallInternal(instance, p1, p2, p3, p4));
+
+ public object StaticCall(TParam1 p1, TParam2 p2, TParam3 p3, TParam4 p4)
+ => CallInternal(default, p1, p2, p3, p4);
+ public object InstanceCall(TOwner instance, TParam1 p1, TParam2 p2, TParam3 p3, TParam4 p4)
+ => CallInternal(instance, p1, p2, p3, p4);
+
+ public TRet StaticCall(TParam1 p1, TParam2 p2, TParam3 p3, TParam4 p4)
+ => CallInternalT(default, p1, p2, p3, p4);
+ public TRet InstanceCall(TOwner instance, TParam1 p1, TParam2 p2, TParam3 p3, TParam4 p4)
+ => CallInternalT(instance, p1, p2, p3, p4);
+ }
+}
\ No newline at end of file
diff --git a/ReCap.CommonUI/Util/WinUnmanagedMethods.cs b/ReCap.CommonUI/Util/WinUnmanagedMethods.cs
new file mode 100755
index 0000000..b4aacdb
--- /dev/null
+++ b/ReCap.CommonUI/Util/WinUnmanagedMethods.cs
@@ -0,0 +1,408 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics.CodeAnalysis;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.ComTypes;
+using System.Text;
+
+
+namespace ReCap.CommonUI
+{
+ public static class WinUnmanagedMethods
+ {
+ public const uint WM_NCHITTEST = 0x0084;
+ public const uint WM_NCLBUTTONDOWN = 0x00A1;
+ public const uint WM_NCLBUTTONUP = 0x00A2;
+ public const uint WM_SYSCOMMAND = 0x0112;
+ public const uint WM_LBUTTONDOWN = 0x0201;
+ public const uint WM_LBUTTONUP = 0x0202;
+ public const uint WM_NCMOUSEMOVE = 0x00A0;
+ public const uint WM_MOUSEMOVE = 0x00A0;
+ public const uint WM_NCCALCSIZE = 0x0083;
+ public const uint WM_STYLECHANGING = 0x007C;
+
+
+ public static readonly IntPtr HTBORDER = new IntPtr(18);
+ public static readonly IntPtr HTBOTTOM = new IntPtr(15);
+ public static readonly IntPtr HTBOTTOMLEFT = new IntPtr(16);
+ public static readonly IntPtr HTBOTTOMRIGHT = new IntPtr(17);
+ public static readonly IntPtr HTCAPTION = new IntPtr(2);
+ public static readonly IntPtr HTCLIENT = new IntPtr(1);
+ public static readonly IntPtr HTCLOSE = new IntPtr(20);
+ public static readonly IntPtr HTERROR = new IntPtr(-2);
+ public static readonly IntPtr HTGROWBOX = new IntPtr(4);
+ public static readonly IntPtr HTHELP = new IntPtr(21);
+ public static readonly IntPtr HTHSCROLL = new IntPtr(6);
+ public static readonly IntPtr HTLEFT = new IntPtr(10);
+ public static readonly IntPtr HTMENU = new IntPtr(5);
+ public static readonly IntPtr HTMAXBUTTON = new IntPtr(9);
+ public static readonly IntPtr HTMINBUTTON = new IntPtr(8);
+ public static readonly IntPtr HTNOWHERE = new IntPtr(0);
+ public static readonly IntPtr HTREDUCE = new IntPtr(8);
+ public static readonly IntPtr HTRIGHT = new IntPtr(11);
+ public static readonly IntPtr HTSIZE = new IntPtr(4);
+ public static readonly IntPtr HTSYSMENU = new IntPtr(3);
+ public static readonly IntPtr HTTOP = new IntPtr(12);
+ public static readonly IntPtr HTTOPLEFT = new IntPtr(13);
+ public static readonly IntPtr HTTOPRIGHT = new IntPtr(14);
+ public static readonly IntPtr HTTRANSPARENT = new IntPtr(-1);
+ public static readonly IntPtr HTVSCROLL = new IntPtr(7);
+ public static readonly IntPtr HTZOOM = new IntPtr(9);
+
+
+
+ public static readonly IntPtr SC_CLOSE = new IntPtr(0xF060);
+ public static readonly IntPtr SC_MINIMIZE = new IntPtr(0xF020);
+ public static readonly IntPtr SC_MAXIMIZE = new IntPtr(0xF030);
+
+
+ public delegate IntPtr WndProcDelegate(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
+
+
+ public enum WindowLongParam : int
+ {
+ GWL_WNDPROC = -4,
+ GWL_HINSTANCE = -6,
+ GWL_HWNDPARENT = -8,
+ GWL_ID = -12,
+ GWL_STYLE = -16,
+ GWL_EXSTYLE = -20,
+ GWL_USERDATA = -21
+ }
+
+ public enum ClassLongIndex : int
+ {
+ GCLP_MENUNAME = -8,
+ GCLP_HBRBACKGROUND = -10,
+ GCLP_HCURSOR = -12,
+ GCLP_HICON = -14,
+ GCLP_HMODULE = -16,
+ GCL_CBWNDEXTRA = -18,
+ GCL_CBCLSEXTRA = -20,
+ GCLP_WNDPROC = -24,
+ GCL_STYLE = -26,
+ GCLP_HICONSM = -34,
+ GCW_ATOM = -32
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ public struct WNDCLASSEX
+ {
+ public int cbSize;
+ public int style;
+ public WndProcDelegate lpfnWndProc;
+ public int cbClsExtra;
+ public int cbWndExtra;
+ public IntPtr hInstance;
+ public IntPtr hIcon;
+ public IntPtr hCursor;
+ public IntPtr hbrBackground;
+ public string lpszMenuName;
+ public string lpszClassName;
+ public IntPtr hIconSm;
+ }
+
+
+ [DllImport("user32.dll", SetLastError = true)]
+ public static extern uint GetWindowLongPtr(IntPtr hWnd, int nIndex);
+
+ [DllImport("user32.dll", SetLastError = true, EntryPoint = "GetWindowLong")]
+ public static extern uint GetWindowLong32b(IntPtr hWnd, int nIndex);
+
+ public static uint GetWindowLong(IntPtr hWnd, int nIndex)
+ {
+ if (IntPtr.Size == 4)
+ {
+ return GetWindowLong32b(hWnd, nIndex);
+ }
+ else
+ {
+ return GetWindowLongPtr(hWnd, nIndex);
+ }
+ }
+
+ [DllImport("user32.dll", SetLastError = true, EntryPoint = "SetWindowLong")]
+ private static extern uint SetWindowLong32b(IntPtr hWnd, int nIndex, uint value);
+
+ [DllImport("user32.dll", SetLastError = true, EntryPoint = "SetWindowLongPtr")]
+ private static extern IntPtr SetWindowLong64b(IntPtr hWnd, int nIndex, IntPtr value);
+
+ public static uint SetWindowLong(IntPtr hWnd, int nIndex, uint value)
+ {
+ if (IntPtr.Size == 4)
+ {
+ return SetWindowLong32b(hWnd, nIndex, value);
+ }
+ else
+ {
+ return (uint)SetWindowLong64b(hWnd, nIndex, new IntPtr((uint)value)).ToInt32();
+ }
+ }
+
+ public static IntPtr SetWindowLongPtr(IntPtr hWnd, int nIndex, IntPtr handle)
+ {
+ if (IntPtr.Size == 4)
+ {
+ return new IntPtr(SetWindowLong32b(hWnd, nIndex, (uint)handle.ToInt32()));
+ }
+ else
+ {
+ return SetWindowLong64b(hWnd, nIndex, handle);
+ }
+ }
+
+ [DllImport("user32.dll", EntryPoint = "DefWindowProcW")]
+ public static extern IntPtr DefWindowProc(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam);
+
+ [DllImport("user32.dll")]
+ public static extern IntPtr CallWindowProc(IntPtr lpPrevWndFunc, IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
+
+ public struct POINT
+ {
+ public int X;
+ public int Y;
+
+ public POINT(int x, int y)
+ {
+ X = x;
+ Y = y;
+ }
+
+ public POINT(IntPtr param)
+ {
+ var iParam = param.ToInt32();
+ X = iParam & 0x0000ffff;
+ Y = iParam >> 16;
+ }
+
+ public IntPtr ToWMParam()
+ {
+ //https://social.msdn.microsoft.com/Forums/vstudio/en-US/d9965d14-34ac-48ee-ae4f-85cee689cc33/how-to-make-lparam?forum=vbgeneral
+
+ var retList = new List();
+ byte[] xByte = BitConverter.GetBytes(X);
+ byte[] yByte = BitConverter.GetBytes(Y);
+ retList.Add(xByte[0]);
+ retList.Add(xByte[1]);
+ retList.Add(yByte[0]);
+ retList.Add(yByte[1]);
+ return new IntPtr(BitConverter.ToInt32(retList.ToArray(), 0));
+ }
+ }
+
+ [DllImport("user32.dll", CharSet = CharSet.Auto)]
+ public static extern IntPtr SendMessage(/*IntPtr lpPrevWndFunc, */IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
+ //(IntPtr hWnd, uint Msg, nuint wParam, StringBuilder lParam);
+
+ public struct RECT
+ {
+ public int left;
+ public int top;
+ public int right;
+ public int bottom;
+
+ public int Width => right - left;
+ public int Height => bottom - top;
+ /*public RECT(Rect rect)
+ {
+ left = (int)rect.X;
+ top = (int)rect.Y;
+ right = (int)(rect.X + rect.Width);
+ bottom = (int)(rect.Y + rect.Height);
+ }*/
+
+ public RECT(POINT topLeft, POINT bottomRight)
+ {
+ left = topLeft.X;
+ top = topLeft.Y;
+ right = bottomRight.X;
+ bottom = bottomRight.Y;
+ }
+
+ public void Offset(POINT pt)
+ {
+ left += pt.X;
+ right += pt.X;
+ top += pt.Y;
+ bottom += pt.Y;
+ }
+
+ public bool Contains(POINT point)
+ {
+ return
+ (point.X >= left)
+ && (point.Y >= top)
+ && (point.X < right)
+ && (point.Y < bottom)
+ ;
+ }
+ }
+
+ [DllImport("user32.dll")]
+ public static extern bool ScreenToClient(IntPtr hWnd, ref POINT lpPoint);
+
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct WINDOWPOS
+ {
+ public IntPtr hwnd;
+ public IntPtr hwndInsertAfter;
+ public int x;
+ public int y;
+ public int cx;
+ public int cy;
+ public uint flags;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ public struct NCCALCSIZE_PARAMS
+ {
+ [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
+ public RECT[] rgrc;
+ public WINDOWPOS lppos;
+ }
+
+
+ public static readonly IntPtr WVR_REDRAW = new IntPtr(0x0300);
+
+
+ [DllImport("user32.dll", SetLastError = true)]
+ internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
+
+ public const uint WS_CAPTION = 0x00C00000;
+
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct RTL_OSVERSIONINFOEX
+ {
+ internal uint dwOSVersionInfoSize;
+ internal uint dwMajorVersion;
+ internal uint dwMinorVersion;
+ internal uint dwBuildNumber;
+ internal uint dwPlatformId;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
+ internal string szCSDVersion;
+ }
+
+ [DllImport("ntdll.dll")]
+ internal static extern int RtlGetVersion(ref RTL_OSVERSIONINFOEX lpVersionInformation);
+
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct MARGINS
+ {
+ public int cxLeftWidth;
+ public int cxRightWidth;
+ public int cyTopHeight;
+ public int cyBottomHeight;
+ }
+ [DllImport("dwmapi.dll")]
+ internal static extern int DwmExtendFrameIntoClientArea(IntPtr hwnd, ref MARGINS margins);
+
+
+#if NO
+ [DllImport("user32.dll")]
+ internal static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref WindowCompositionAttributeData data);
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct WindowCompositionAttributeData
+ {
+ public WindowCompositionAttribute Attribute;
+ public IntPtr Data;
+ public int SizeOfData;
+ }
+
+ internal enum WindowCompositionAttribute
+ {
+ WCA_ACCENT_POLICY = 19
+ }
+
+ internal enum AccentState
+ {
+ ACCENT_DISABLED = 0,
+ ACCENT_ENABLE_GRADIENT = 1,
+ ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
+ ACCENT_ENABLE_BLURBEHIND = 3,
+ ACCENT_INVALID_STATE = 4
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct AccentPolicy
+ {
+ public AccentState AccentState;
+ public int AccentFlags;
+ public int GradientColor;
+ public int AnimationId;
+ }
+#else
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct WindowCompositionAttributeData
+ {
+ public WindowCompositionAttribute Attribute;
+ public IntPtr Data;
+ public int SizeOfData;
+ }
+
+ internal enum WindowCompositionAttribute
+ {
+ WCA_ACCENT_POLICY = 19,
+ WCA_USEDARKMODECOLORS = 26
+ }
+
+ [DllImport("user32.dll")]
+ internal static extern int SetWindowCompositionAttribute(IntPtr hwnd, ref WindowCompositionAttributeData data);
+
+ internal enum AccentState
+ {
+ ACCENT_DISABLED = 0,
+ ACCENT_ENABLE_GRADIENT = 1,
+ ACCENT_ENABLE_TRANSPARENTGRADIENT = 2,
+ ACCENT_ENABLE_BLURBEHIND_BUT_ITS_PER_PIXEL_ALPHA_ON_WINDOWS_8 = 3,
+ ACCENT_ENABLE_ACRYLICBLURBEHIND = 4,
+ ACCENT_INVALID_STATE = 5,
+ ACCENT_ENABLE_PER_PIXEL_ALPHA_I_GUESS = 6
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ internal struct AccentPolicy
+ {
+ public AccentState AccentState;
+ public int AccentFlags;
+ public int GradientColor;
+ public int AnimationId;
+ }
+#endif
+
+ [DllImport("dwmapi.dll", PreserveSig = true)]
+ public static extern int DwmSetWindowAttribute(IntPtr hwnd, Int32 attr, ref Int32 attrValue, Int32 attrSize);
+
+ [Flags]
+ public enum DwmWindowAttribute
+ {
+ NCRenderingEnabled = 1,
+ NCRenderingPolicy,
+ TransitionsForceDisabled,
+ AllowNCPaint,
+ CaptionButtonBounds,
+ NonClientRtlLayout,
+ ForceIconicRepresentation,
+ Flip3DPolicy,
+ ExtendedFrameBounds,
+ HasIconicBitmap,
+ DisallowPeek,
+ ExcludedFromPeek,
+ Last
+ }
+
+ [Flags]
+ public enum DwmNCRenderingPolicy
+ {
+ UseWindowStyle,
+ Disabled,
+ Enabled,
+ Last
+ }
+ }
+}
\ No newline at end of file
diff --git a/ReCap.Hub/.gitignore b/ReCap.Hub/.gitignore
new file mode 100644
index 0000000..913207c
--- /dev/null
+++ b/ReCap.Hub/.gitignore
@@ -0,0 +1,44 @@
+*.swp
+*.*~
+project.lock.json
+.DS_Store
+*.pyc
+nupkg/
+
+# Visual Studio Code
+.vscode/
+
+# Rider
+.idea/
+
+# Visual Studio
+.vs/
+
+# Fleet
+.fleet/
+
+# Code Rush
+.cr/
+
+# User-specific files
+*.suo
+*.user
+*.userosscache
+*.sln.docstates
+
+# Build results
+[Dd]ebug/
+[Dd]ebugPublic/
+[Rr]elease/
+[Rr]eleases/
+x64/
+x86/
+build/
+bld/
+[Bb]in/
+[Oo]bj/
+[Oo]ut/
+[Pp]ublish/
+msbuild.log
+msbuild.err
+msbuild.wrn
\ No newline at end of file
diff --git a/ReCap.Hub/App.axaml b/ReCap.Hub/App.axaml
new file mode 100755
index 0000000..6f3aa63
--- /dev/null
+++ b/ReCap.Hub/App.axaml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ReCap.Hub/App.axaml.cs b/ReCap.Hub/App.axaml.cs
new file mode 100755
index 0000000..8453e8a
--- /dev/null
+++ b/ReCap.Hub/App.axaml.cs
@@ -0,0 +1,187 @@
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Runtime.InteropServices;
+using System.Threading.Tasks;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Markup.Xaml;
+using Avalonia.Threading;
+using ReCap.CommonUI;
+using ReCap.Hub.Data;
+using ReCap.Hub.Localization;
+using ReCap.Hub.ViewModels;
+using ReCap.Hub.Views;
+
+namespace ReCap.Hub
+{
+ public partial class App
+ : Application
+ {
+ Window _mainWindow = null;
+
+ public override void Initialize()
+ {
+ /*var bodyFont = new FontFamily("avares://ReCap.Hub/Res/UI/Font/Body/SingleBold#RobotoCondensed");
+ FontManager.Current.GetOrAddGlyphTypeface(new Typeface(bodyFont, weight: FontWeight.Black));
+ FontManager.Current.GetOrAddGlyphTypeface(new Typeface(bodyFont, weight: FontWeight.DemiBold));
+ FontManager.Current.GetOrAddGlyphTypeface(new Typeface(bodyFont, weight: FontWeight.SemiBold));
+
+ var bodyFontLight = new FontFamily("avares://ReCap.Hub/Res/UI/Font/Body/SingleLight#Roboto Condensed");
+ FontManager.Current.GetOrAddGlyphTypeface(new Typeface(bodyFontLight, weight: FontWeight.SemiLight));
+
+ Resources.Add("BodyFont", bodyFont);*/
+ AvaloniaXamlLoader.Load(this);
+ }
+
+ ReCapTheme _reCapTheme = null;
+ public bool UseManagedWindowChrome
+ {
+ get => _reCapTheme?.UseManagedChrome ?? false;
+ set
+ {
+ if (_reCapTheme != null)
+ _reCapTheme.UseManagedChrome = value;
+ }
+ }
+
+ public override void OnFrameworkInitializationCompleted()
+ {
+ var dict = UILanguageManager.Instance.Dictionary;
+ Resources.MergedDictionaries.Add(dict);
+
+ base.OnFrameworkInitializationCompleted();
+ var styles = Styles;
+ foreach (var style in styles)
+ {
+ if (style is ReCapTheme reCapTheme)
+ {
+ _reCapTheme = reCapTheme;
+ break;
+ }
+ }
+ // TODO: Restore once managed decorations actually work
+ //UseManagedWindowChrome = GetShouldUseManagedWindowDecorationsByDefault();
+
+ var lifetime = ApplicationLifetime;
+ if (lifetime == null)
+ throw new NullReferenceException($"{nameof(lifetime)} must not be null.");
+
+ if (!(lifetime is IClassicDesktopStyleApplicationLifetime desktop))
+ throw new Exception($"{nameof(lifetime)} must implement {nameof(IClassicDesktopStyleApplicationLifetime)}, but was of type {lifetime.GetType().FullName} which doesn't.");
+
+
+ _mainWindow = new MainWindow()
+ {
+ };
+ desktop.MainWindow = _mainWindow;
+
+ LocalServer.ServerStarted += OnLocalServerStarted;
+ LocalServer.ServerExited += OnLocalServerExited;
+ GameLaunchService.GameExited += OnGameExited;
+
+
+ int gameConfigsCount = HubData.Instance.GameConfigs.Count;
+ if (gameConfigsCount <= 0)
+ {
+ _mainWindow?.Hide();
+ //string gamePath = null;
+ //string savesPath = null;
+
+ //TEMPORARY
+ //gamePath = @"E:\Programs (x86)\Electronic Arts\Darkspore";
+ ////////savesPath = Path.Combine(LocalServer.Instance.ServerDirPath, "storage", "users");
+
+
+ Task.Run(async () =>
+ {
+ var gamePaths = await DialogDisplay.ShowDialog(new LocateDarksporeViewModel(false));
+
+ string gameVersion = null;
+
+ string installPath = gamePaths.DarksporeInstallPath;
+ string exePath = Path.Combine(installPath, "DarksporeBin", "Darkspore.exe");
+ if (File.Exists(exePath))
+ {
+ var pe = new PeNet.PeFile(exePath);
+ var strFileInfo = pe.Resources.VsVersionInfo.StringFileInfo;
+ var stringTables = strFileInfo.StringTable;
+
+ if (stringTables.Length > 0)
+ gameVersion = stringTables[0].ProductVersion;
+
+ if (string.IsNullOrEmpty(gameVersion) || string.IsNullOrWhiteSpace(gameVersion))
+ {
+ Debug.WriteLine("PeFile failed to retrieve exe version");
+
+ // try our luck by falling back to FileVersionInfo (which currently only works on Windows)
+ var gameVersionInfo = FileVersionInfo.GetVersionInfo(exePath);
+ gameVersion = gameVersionInfo.ProductVersion;
+ }
+ }
+ if (string.IsNullOrEmpty(gameVersion) || string.IsNullOrWhiteSpace(gameVersion))
+ gameVersion = "?.?.?.?";
+
+ string gameConfigName = $"Darkspore v{gameVersion}";
+
+ GameConfigViewModel gameConfig =
+ new GameConfigViewModel(installPath, gamePaths.WineExecutable, gamePaths.WinePrefix)
+ {
+ Title = gameConfigName
+ }
+ ;
+ HubData.Instance.GameConfigs.Add(gameConfig);
+
+ if (gameConfig.Saves.Count <= 0)
+ {
+ var saveGame = await gameConfig.CreateSaveGame(false);
+ gameConfig.SelectedSave = saveGame;
+ }
+
+ HubData.Instance.Save();
+ Dispatcher.UIThread.Post(() => ShowMainWindow(desktop));
+ });
+ }
+ else if ((gameConfigsCount == 1) && TimeHelper.TryGetNewest(HubData.Instance.GameConfigs, vm => vm.LastLaunchTime, out GameConfigViewModel gameConfig) && (gameConfig.Saves.Count <= 0))
+ {
+ Task.Run(async () =>
+ {
+ var saveGame = await gameConfig.CreateSaveGame(false);
+ gameConfig.SelectedSave = saveGame;
+
+ HubData.Instance.Save();
+ Dispatcher.UIThread.Post(() => ShowMainWindow(desktop));
+ });
+ }
+ else
+ {
+ ShowMainWindow(desktop);
+ }
+ }
+
+ void ShowMainWindow(IClassicDesktopStyleApplicationLifetime desktop)
+ {
+ _mainWindow.DataContext = new MainViewModel();
+ _mainWindow?.Show();
+ }
+
+ public static bool GetShouldUseManagedWindowDecorationsByDefault()
+ {
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ return GetShouldUseManagedWindowDecorationsByDefault_Windows();
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
+ {
+ return GetShouldUseManagedWindowDecorationsByDefault_Linux();
+ }
+ else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
+ {
+ return GetShouldUseManagedWindowDecorationsByDefault_macOS();
+ }
+
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ReCap.Hub/App`linux.cs b/ReCap.Hub/App`linux.cs
new file mode 100644
index 0000000..408a1ea
--- /dev/null
+++ b/ReCap.Hub/App`linux.cs
@@ -0,0 +1,45 @@
+using Avalonia;
+using System;
+using System.Diagnostics;
+
+namespace ReCap.Hub
+{
+ public partial class App
+ : Application
+ {
+ static bool GetShouldUseManagedWindowDecorationsByDefault_Linux()
+ {
+ Debug.WriteLine($"{nameof(GetShouldUseManagedWindowDecorationsByDefault_Linux)}()");
+ string xdgCurrentDesktop = Environment.GetEnvironmentVariable("XDG_CURRENT_DESKTOP");
+ if (xdgCurrentDesktop != null)
+ {
+ string[] desktopEnvs = xdgCurrentDesktop.Contains(':')
+ ? xdgCurrentDesktop.Split(':', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
+ : new[]{ xdgCurrentDesktop }
+ ;
+
+ foreach (string desktopEnv in desktopEnvs)
+ {
+ if (desktopEnv == "KDE")
+ {
+ Debug.WriteLine("KDE - default to system decorations");
+ return false;
+ }
+
+ if ((desktopEnv == "GNOME") || (desktopEnv == "GNOME-Flashback"))
+ {
+ Debug.WriteLine("GNOME - default to managed decorations");
+ return true;
+ }
+
+ // TODO: Others
+ // https://wiki.archlinux.org/title/Environment_variables#Examples
+ }
+ }
+
+ //TODO: Should fallback be system or managed decorations?
+ Debug.WriteLine("FALLBACK CASE");
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ReCap.Hub/App`macOS.cs b/ReCap.Hub/App`macOS.cs
new file mode 100644
index 0000000..6a25f97
--- /dev/null
+++ b/ReCap.Hub/App`macOS.cs
@@ -0,0 +1,14 @@
+using Avalonia;
+using System;
+
+namespace ReCap.Hub
+{
+ public partial class App
+ : Application
+ {
+ static bool GetShouldUseManagedWindowDecorationsByDefault_macOS()
+ {
+ return false;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ReCap.Hub/App`platform.cs b/ReCap.Hub/App`platform.cs
new file mode 100755
index 0000000..f82dd3d
--- /dev/null
+++ b/ReCap.Hub/App`platform.cs
@@ -0,0 +1,58 @@
+using Avalonia;
+using ReCap.CommonUI;
+using ReCap.Hub.Data;
+using ReCap.Hub.ViewModels;
+using ReCap.Hub.Views;
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Threading.Tasks;
+using System.Linq;
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Threading;
+
+namespace ReCap.Hub
+{
+ public partial class App : Application
+ {
+ void OnLocalServerStarted(object sender, EventArgs e)
+ {
+ if (OperatingSystem.IsWindows())
+ ServerStarted_Windows();
+
+ _mainWindow?.Hide();
+ }
+
+
+ void OnLocalServerExited(object sender, EventArgs e)
+ => Dispatcher.UIThread.Post(() =>
+ {
+#if EXIT_HUB_AFTER_GAME_EXIT
+ Dispatcher.UIThread.Post(() => Environment.Exit(0));
+#else
+ ShowMainWindow(HubData.Instance.AutoCloseServer);
+#endif
+ });
+
+ void OnGameExited(object sender, EventArgs e)
+ {
+ if (HubData.Instance.AutoCloseServer)
+ return;
+ ShowMainWindow(false);
+ }
+
+ void ShowMainWindow(bool closeServer)
+ {
+ _mainWindow?.Show();
+
+ if (closeServer && OperatingSystem.IsWindows())
+ {
+ ServerExited_Windows();
+ }
+ else
+ {
+ Dispatcher.UIThread.Post(() => _mainWindow?.Activate(), DispatcherPriority.Render);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ReCap.Hub/App`windows.cs b/ReCap.Hub/App`windows.cs
new file mode 100755
index 0000000..fb3fcec
--- /dev/null
+++ b/ReCap.Hub/App`windows.cs
@@ -0,0 +1,48 @@
+using Avalonia;
+using ReCap.CommonUI;
+using System;
+
+namespace ReCap.Hub
+{
+ public partial class App
+ : Application
+ {
+#pragma warning disable CA1416
+ void ServerStarted_Windows()
+ {
+ IntPtr cmd = WindowsPInvoke.GetConsoleWindow();
+ WindowsPInvoke.ShowWindow(cmd, 4);
+
+ if (!_mainWindow.TryGetHWnd(out IntPtr hMainWnd))
+ return;
+
+ if (WindowsPInvoke.GetWindowRect(hMainWnd, out WindowsPInvoke.RECT mainWinRect))
+ {
+ var flags = WindowsPInvoke.SetWindowPosFlags.IgnoreResize;
+ WindowsPInvoke.SetWindowPos(cmd, hMainWnd, mainWinRect.X, mainWinRect.Y, 0, 0, flags);
+ }
+ }
+
+ void ServerExited_Windows()
+ {
+ IntPtr hCmdWnd = WindowsPInvoke.GetConsoleWindow();
+ WindowsPInvoke.ShowWindow(hCmdWnd, 0);
+ if (!_mainWindow.TryGetHWnd(out IntPtr hMainWnd))
+ return;
+
+ if (WindowsPInvoke.GetWindowRect(hCmdWnd, out WindowsPInvoke.RECT cmdRect))
+ {
+ var flags = WindowsPInvoke.SetWindowPosFlags.IgnoreResize | WindowsPInvoke.SetWindowPosFlags.ShowWindow;
+ // | PInvoke.SetWindowPosFlags.HideWindow); //| PInvoke.SetWindowPosFlags.DoNotActivate | PInvoke.SetWindowPosFlags.DoNotSendChangingEvent | PInvoke.SetWindowPosFlags.DoNotRedraw); // | PInvoke.SetWindowPosFlags.ShowWindow);
+
+ WindowsPInvoke.SetWindowPos(hMainWnd, hCmdWnd, cmdRect.X, cmdRect.Y, 0, 0, flags);
+ }
+ }
+#pragma warning restore CA1416
+
+ static bool GetShouldUseManagedWindowDecorationsByDefault_Windows()
+ {
+ return true;
+ }
+ }
+}
\ No newline at end of file
diff --git a/ReCap.Hub/Assets/Hero/0x6E76B39A.png b/ReCap.Hub/Assets/Hero/0x6E76B39A.png
new file mode 100644
index 0000000..027e1c9
Binary files /dev/null and b/ReCap.Hub/Assets/Hero/0x6E76B39A.png differ
diff --git a/ReCap.Hub/Assets/Level/Mask.png b/ReCap.Hub/Assets/Level/Mask.png
new file mode 100644
index 0000000..2212df3
Binary files /dev/null and b/ReCap.Hub/Assets/Level/Mask.png differ
diff --git a/ReCap.Hub/Assets/Level/Overlay.png b/ReCap.Hub/Assets/Level/Overlay.png
new file mode 100644
index 0000000..443952c
Binary files /dev/null and b/ReCap.Hub/Assets/Level/Overlay.png differ
diff --git a/ReCap.Hub/Assets/Level/zelems_3.pdn b/ReCap.Hub/Assets/Level/zelems_3.pdn
new file mode 100644
index 0000000..2d5a943
--- /dev/null
+++ b/ReCap.Hub/Assets/Level/zelems_3.pdn
@@ -0,0 +1,2448 @@
+PDN3D