Compare commits
462 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8ba7351206 | |||
| 7c901a56e5 | |||
| 8ba44e75a4 | |||
| 7cadc8d331 | |||
| 7debd885b9 | |||
| 44a9c52c44 | |||
| dcc444173d | |||
| d3c4b5b8c1 | |||
| 56236b0579 | |||
| c2a588f738 | |||
| 09331b601b | |||
| 17d7716e41 | |||
| 0344cde98f | |||
| 9f35f175ab | |||
| cabf8736c7 | |||
| 93344a33d3 | |||
| 3898df1b68 | |||
| 33909cf931 | |||
| 3bc70c147b | |||
| 70dea56d44 | |||
| 348e15475f | |||
| fe568cf16a | |||
| 1066a38130 | |||
| 2494c3cb23 | |||
| ecc34320d1 | |||
|
|
9f078a6e3c | ||
|
|
b4d1e6197c | ||
|
|
d14a4f1f66 | ||
|
|
1e43b031ba | ||
|
|
41fd7b724e | ||
|
|
2a1706decb | ||
|
|
ab7de52531 | ||
|
|
1891b9e367 | ||
|
|
3ac7dfbd3a | ||
|
|
2853273205 | ||
|
|
2201dd681e | ||
|
|
013dab4ba7 | ||
|
|
cf501945a3 | ||
|
|
ab4703c3dd | ||
|
|
4ce853d892 | ||
|
|
6cdd56ad11 | ||
|
|
66122e6e3b | ||
|
|
c444661884 | ||
|
|
91a8a670d5 | ||
|
|
dbd5566ee0 | ||
|
|
ad2d4a2626 | ||
|
|
148f03205f | ||
|
|
2c1f835528 | ||
|
|
8038e045b0 | ||
|
|
7a635e2896 | ||
|
|
a40a5721f3 | ||
|
|
e4cf4c9f17 | ||
|
|
5299afa276 | ||
|
|
8e8e41d5e1 | ||
|
|
153e45c345 | ||
|
|
7bb365c57b | ||
|
|
8397a81428 | ||
|
|
17c484b97b | ||
|
|
3b740659f5 | ||
|
|
2913bb39e8 | ||
|
|
8209639261 | ||
|
|
a580d6785f | ||
| 8b22ffe007 | |||
| 24f7ec4a54 | |||
| 55d55212c3 | |||
|
|
1142fa68ea | ||
|
|
305f725394 | ||
|
|
8a297a6fd4 | ||
|
|
d717430256 | ||
|
|
8804738193 | ||
|
|
9b11461eaf | ||
|
|
d879b8e064 | ||
|
|
f132198ead | ||
|
|
5e0d90af2e | ||
|
|
736119fdc6 | ||
|
|
5259c41b40 | ||
|
|
4a6f2f8821 | ||
|
|
529de24da4 | ||
|
|
fc3d15c544 | ||
|
|
261c4a7e88 | ||
|
|
ccd619f659 | ||
|
|
35bbd52f89 | ||
|
|
ea45aa9b19 | ||
|
|
655c377da8 | ||
|
|
5498cbf3bf | ||
|
|
10a343a490 | ||
|
|
b2faad9634 | ||
|
|
786ab54f84 | ||
|
|
d41d153cff | ||
|
|
89bd733142 | ||
|
|
5d2a1e0507 | ||
|
|
22ff68b89f | ||
|
|
fe41ef619b | ||
|
|
3870a013fa | ||
|
|
ebd890a0da | ||
|
|
964a1940c4 | ||
|
|
b11af95ec7 | ||
|
|
e8de6c37fc | ||
|
|
af41cefaac | ||
|
|
900a96938b | ||
|
|
c58d43ac1e | ||
|
|
0122ee94a5 | ||
|
|
dfb541011d | ||
|
|
85a04f8e81 | ||
|
|
531c75bff9 | ||
|
|
12f70572b0 | ||
|
|
7090e85224 | ||
|
|
e5e1f945ea | ||
|
|
e1cf41b94b | ||
|
|
d4bf8368b1 | ||
|
|
6588a71879 | ||
|
|
d700df6afb | ||
| 35d46e23a8 | |||
| f1fc086612 | |||
|
|
7b4e509140 | ||
|
|
c168ce3a7e | ||
|
|
e1dcd290b1 | ||
|
|
009e1aaebb | ||
|
|
fe9996dd4f | ||
|
|
d1e54b821b | ||
|
|
8877aac8cb | ||
|
|
a61096ffa5 | ||
|
|
751c1f20dc | ||
|
|
f40cf6539a | ||
|
|
8e4f7babf3 | ||
|
|
e18b059234 | ||
|
|
e3114c29af | ||
|
|
3539f84c9a | ||
|
|
5b0c6d1aff | ||
|
|
1b72b14376 | ||
|
|
32af6ede73 | ||
|
|
a79fb237e5 | ||
|
|
ec510425a1 | ||
|
|
bf772a5eb9 | ||
|
|
fe3a9fbd67 | ||
|
|
090b9ea0c1 | ||
|
|
ddfaeddb5f | ||
|
|
abe938c30a | ||
|
|
cf02fecadc | ||
|
|
54c24f8434 | ||
|
|
35ab0f4261 | ||
|
|
73342615d1 | ||
|
|
d64108a5c1 | ||
|
|
1dfa92b0c3 | ||
| d56493da54 | |||
| 16b0228394 | |||
|
|
cb3e8e4112 | ||
|
|
5f4aee71b8 | ||
|
|
02403377cd | ||
| 6436fb3bde | |||
|
|
a1adab1156 | ||
|
|
919e118a2f | ||
|
|
f38df259a7 | ||
|
|
ec10e3bb30 | ||
|
|
224c2c049e | ||
|
|
8509761d67 | ||
|
|
0d8691045b | ||
|
|
bd727ae189 | ||
|
|
4bfda76666 | ||
|
|
a030978558 | ||
|
|
2aff3d76ca | ||
|
|
8312659275 | ||
|
|
55ce33bc1c | ||
|
|
1613bdcd06 | ||
|
|
a67dc00fa3 | ||
| 1c82c73bc0 | |||
|
|
a05fe5ce9b | ||
|
|
8899e3ebb7 | ||
|
|
727ff8be95 | ||
|
|
a8d97f1daa | ||
|
|
488485e23e | ||
|
|
79138dfaf0 | ||
|
|
f52059522b | ||
| 691ac6d439 | |||
|
|
6fc056cba2 | ||
|
|
54cb82cbda | ||
|
|
b8c9130ae4 | ||
|
|
c2e1b92cce | ||
|
|
6113325e07 | ||
|
|
bea7e1526d | ||
|
|
abc75e6c3d | ||
|
|
dfc1db672d | ||
|
|
5b71591998 | ||
|
|
4dabf4bf01 | ||
|
|
210c443b30 | ||
|
|
f95e7e96bf | ||
|
|
735aa70b53 | ||
|
|
b1fd178341 | ||
|
|
0bb21ef4a0 | ||
|
|
2a4a5d2519 | ||
|
|
892ab47b7a | ||
|
|
7f6805aac6 | ||
|
|
d56d624f0f | ||
|
|
fd91e912fe | ||
|
|
7106791186 | ||
|
|
a0f379f613 | ||
|
|
c0847f6789 | ||
|
|
831289afc3 | ||
| 7ba97f3c32 | |||
| 992436b47c | |||
| 7614481d78 | |||
| 07371ddfdf | |||
|
|
50c29f6a9b | ||
|
|
a4877c6294 | ||
|
|
c9bebc0700 | ||
|
|
26867bfd8f | ||
|
|
dfd6df7f42 | ||
|
|
092681aea7 | ||
|
|
3a2f4843ba | ||
|
|
db6cdc3ce0 | ||
|
|
b23aa6cebd | ||
|
|
2676daabf1 | ||
|
|
c82e67083f | ||
|
|
175fd31431 | ||
|
|
3b1a96582a | ||
|
|
2b46f04baf | ||
|
|
106b48f4d5 | ||
|
|
732b34d28b | ||
|
|
116539ce34 | ||
|
|
e8421d4274 | ||
|
|
0b9ee23a5c | ||
|
|
2d2841d59e | ||
|
|
a0c2f6a51e | ||
|
|
1d946afe82 | ||
|
|
6ea519b55a | ||
|
|
2d6c49ee20 | ||
|
|
59b250f091 | ||
|
|
6c347f08b6 | ||
|
|
304f24764b | ||
|
|
3dac26ffda | ||
|
|
f51a442357 | ||
|
|
d4145179a9 | ||
| bf5e5d1254 | |||
| adbe43c2c2 | |||
| 974e3e192b | |||
| 2283a15172 | |||
| c4d5e50f22 | |||
| 86d90605fc | |||
| db71bf2868 | |||
| fef124a01d | |||
| 272977a521 | |||
| dedb3d57fd | |||
|
|
0fc507e238 | ||
|
|
9e9013ec43 | ||
|
|
0c50fa9816 | ||
|
|
83ccb79fa3 | ||
|
|
8b72c063a8 | ||
|
|
e0791eacad | ||
|
|
11ec018933 | ||
|
|
8ef1cad6fb | ||
|
|
6885e561db | ||
|
|
806bff19f4 | ||
|
|
949057b1c3 | ||
|
|
5c23f4ac09 | ||
|
|
cdd53f09b9 | ||
|
|
f3210608ae | ||
|
|
f01784108d | ||
|
|
30c1068a13 | ||
|
|
3f3df090f4 | ||
|
|
390f574662 | ||
|
|
48a09c9783 | ||
|
|
981109a6f1 | ||
|
|
2f8428db1a | ||
|
|
d0ec3fa2e2 | ||
|
|
9533289e57 | ||
|
|
0f485cf77c | ||
|
|
8c8b4613d2 | ||
|
|
3b872f08a8 | ||
|
|
e89e0159bf | ||
|
|
857d2c26f4 | ||
|
|
49e70637db | ||
|
|
72a151816a | ||
|
|
528b20dc00 | ||
|
|
ce2d2b78c4 | ||
|
|
b22c42b9e3 | ||
|
|
377d25a1fd | ||
|
|
32a60c3b5c | ||
|
|
3f40aff01f | ||
|
|
09563caf37 | ||
|
|
130fc5b54d | ||
|
|
e15a848ac6 | ||
|
|
1729fe6993 | ||
|
|
cc01e88ce8 | ||
|
|
f18715a497 | ||
|
|
d47a191d5c | ||
|
|
afdae7f670 | ||
|
|
7c4b8758ea | ||
|
|
f22e559e83 | ||
|
|
9731437717 | ||
|
|
6f7bb8dbf2 | ||
|
|
3dd83c52bf | ||
|
|
949ac08643 | ||
|
|
4948b1b86a | ||
|
|
e5bf0e1b9f | ||
|
|
b776465919 | ||
|
|
82181b28b0 | ||
|
|
eb07fd7b9a | ||
|
|
79dbad6547 | ||
|
|
94884fc39a | ||
|
|
aec5ef8332 | ||
|
|
8e4783a0c6 | ||
|
|
c23f2b61cc | ||
|
|
6481897ffa | ||
|
|
499a7c6129 | ||
|
|
84fdf9cc80 | ||
|
|
f8d023ed5c | ||
|
|
5ca61d8568 | ||
|
|
58998f4576 | ||
|
|
c486577b07 | ||
|
|
a69c8ce6a2 | ||
|
|
e527783e55 | ||
|
|
4d9c92dd49 | ||
|
|
9b01229e58 | ||
|
|
e3a030fad8 | ||
|
|
cb878294ea | ||
|
|
b2fc5e8fd3 | ||
|
|
4fb42319ef | ||
|
|
1bd1aca0f0 | ||
|
|
b433312042 | ||
|
|
1041b1b86d | ||
|
|
1ace5fd10d | ||
|
|
cfc9f73744 | ||
|
|
2418167182 | ||
|
|
52090d3a6b | ||
|
|
73f68c102d | ||
|
|
862dd1e5f1 | ||
| 58351d1989 | |||
|
|
6705205e2f | ||
|
|
2cdd0ff644 | ||
|
|
69ae841f64 | ||
|
|
7f8700288f | ||
|
|
f87dec6ca6 | ||
|
|
65a6c0aed5 | ||
|
|
f6dd0decfb | ||
|
|
816984542a | ||
|
|
3837e8b263 | ||
|
|
47b3141f18 | ||
|
|
e10ee3e55a | ||
|
|
0a4e89e29b | ||
|
|
0765fa92b5 | ||
|
|
2529312152 | ||
|
|
3404643636 | ||
|
|
6b9f6ac82e | ||
|
|
ab5bb79754 | ||
|
|
58f95d6ce3 | ||
|
|
1cd2f6a070 | ||
|
|
35ddfc2455 | ||
|
|
17d1d87268 | ||
|
|
fd871ce830 | ||
|
|
b4a4a8a591 | ||
|
|
24e4015425 | ||
|
|
c670887b1a | ||
|
|
d3cd6a461b | ||
|
|
2625a9d762 | ||
|
|
4fdd9a242b | ||
|
|
a6e8e6f749 | ||
|
|
03eabbcf63 | ||
|
|
13f94dcf11 | ||
|
|
3b44062eb0 | ||
|
|
1457637707 | ||
|
|
d28567111f | ||
|
|
1c7f06e570 | ||
|
|
63cc0fef2e | ||
|
|
57084b3d6c | ||
|
|
fa23619f08 | ||
|
|
1f2456fc67 | ||
|
|
0b71e906a6 | ||
|
|
2e59c35a44 | ||
|
|
6f2bd0e932 | ||
|
|
6a883bc7c6 | ||
|
|
17de6388ca | ||
|
|
e028d263f1 | ||
|
|
6962ed6730 | ||
|
|
b66d50ae1b | ||
|
|
675ce71935 | ||
|
|
833f844d59 | ||
|
|
af08dc1c69 | ||
|
|
07628d2ec7 | ||
|
|
aac3dbfe09 | ||
|
|
185f24ce49 | ||
| 77e29109ee | |||
| 8d89b9efb0 | |||
|
|
b2fee31a13 | ||
|
|
fc7628e2ee | ||
|
|
2e3e4959d6 | ||
|
|
f22105c2c3 | ||
|
|
533902d185 | ||
|
|
68653fa91f | ||
|
|
dc0aa61a14 | ||
|
|
ee790ff3a9 | ||
|
|
a2a3926aee | ||
|
|
9a70344c1f | ||
|
|
44006dd533 | ||
|
|
f6aabf2d14 | ||
|
|
dc1f15f18d | ||
|
|
7d7808af8f | ||
|
|
5029584a9f | ||
|
|
f353d3f114 | ||
|
|
667e8bc293 | ||
|
|
2edb9cc4d8 | ||
|
|
7018666a8c | ||
|
|
f04926ad94 | ||
| 50f5f0acd9 | |||
|
|
3745979b81 | ||
|
|
db15f6f08a | ||
|
|
e1a2f51d5a | ||
|
|
a8e1fd7a4a | ||
|
|
d46ef6ac92 | ||
|
|
36d21b27c7 | ||
|
|
b1636c27e7 | ||
|
|
5d32fc6c5e | ||
|
|
065dc474c0 | ||
|
|
1fb7b24aad | ||
|
|
f0b72aa025 | ||
|
|
058077736b | ||
|
|
b02f011627 | ||
| ea04c746fd | |||
| 97454fc82e | |||
|
|
4a6afdb108 | ||
|
|
65e852600a | ||
|
|
fedd990c13 | ||
|
|
c0329abe40 | ||
|
|
d8850a56a8 | ||
|
|
e171bb06ec | ||
|
|
3825e07adc | ||
|
|
db8adf7d96 | ||
| e77ae12b9b | |||
|
|
bf4e4aeaf6 | ||
|
|
2107b069db | ||
|
|
ea2005dacb | ||
|
|
d5cded8aaa | ||
|
|
430b22d5d7 | ||
|
|
9d830eb1e2 | ||
|
|
7e3f84f95e | ||
|
|
cddee38d71 | ||
|
|
e030d0461b | ||
|
|
4978c8e0d9 | ||
|
|
dc7b7e6e10 | ||
|
|
1e3eb11b94 | ||
|
|
b15b231b85 | ||
|
|
262992571a | ||
|
|
352bf3f9a7 | ||
|
|
9683868767 | ||
|
|
40284fbbf8 | ||
|
|
0c86a900da | ||
|
|
c1e3eaeab1 | ||
|
|
3c487dff47 | ||
|
|
2260d79e26 | ||
|
|
3209320547 | ||
|
|
d1db06a9bb | ||
|
|
1c1d2fd96f | ||
|
|
2e5ad8c48a | ||
|
|
9a6f866956 | ||
|
|
d8ca8f5985 | ||
|
|
ac36297e27 | ||
|
|
7fef21218e | ||
| 7aa4ae1782 | |||
| dd7739f95e | |||
|
|
203f5d06d1 | ||
|
|
c6515da8c9 | ||
|
|
5d61e45ecd | ||
|
|
2bec653b81 |
@@ -1,4 +1,4 @@
|
||||
# Redirect to our own Git LFS server
|
||||
[lfs]
|
||||
url="https://gitlab.flaxengine.com/flax/flaxengine.git/info/lfs"
|
||||
locksverify = false
|
||||
#url="https://gitlab.flaxengine.com/flax/flaxengine.git/info/lfs"
|
||||
locksverify = false
|
||||
BIN
Content/Engine/DefaultRadialMenu.flax
(Stored with Git LFS)
Normal file
BIN
Content/Engine/DefaultRadialMenu.flax
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
Content/Shaders/Editor/Grid.flax
(Stored with Git LFS)
Normal file
BIN
Content/Shaders/Editor/Grid.flax
(Stored with Git LFS)
Normal file
Binary file not shown.
@@ -3,8 +3,8 @@
|
||||
"Version": {
|
||||
"Major": 1,
|
||||
"Minor": 8,
|
||||
"Revision": 1,
|
||||
"Build": 6511
|
||||
"Revision": 2,
|
||||
"Build": 6512
|
||||
},
|
||||
"Company": "Flax",
|
||||
"Copyright": "Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.",
|
||||
@@ -13,6 +13,7 @@
|
||||
"Configuration": {
|
||||
"UseCSharp": true,
|
||||
"UseLargeWorlds": false,
|
||||
"UseDotNet": true
|
||||
"UseDotNet": true,
|
||||
"UseSDL": true
|
||||
}
|
||||
}
|
||||
@@ -74,6 +74,7 @@
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/UserRules/=UNION/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CppNaming/UserRules/=UNION_005FMEMBER/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="aa_bb" /></s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=AI/@EntryIndexedValue">AI</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=ARGB/@EntryIndexedValue">ARGB</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=LO/@EntryIndexedValue">LO</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RPC/@EntryIndexedValue">RPC</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SDK/@EntryIndexedValue">SDK</s:String>
|
||||
|
||||
@@ -61,6 +61,8 @@ namespace FlaxEditor.Content.GUI
|
||||
private bool _isRubberBandSpanning;
|
||||
private Float2 _mousePressLocation;
|
||||
private Rectangle _rubberBandRectangle;
|
||||
private bool _isCutting;
|
||||
private List<ContentItem> _cutItems = new List<ContentItem>();
|
||||
|
||||
private bool _validDragOver;
|
||||
private DragActors _dragActors;
|
||||
@@ -83,9 +85,9 @@ namespace FlaxEditor.Content.GUI
|
||||
public event Action<List<ContentItem>> OnDelete;
|
||||
|
||||
/// <summary>
|
||||
/// Called when user wants to paste the files/folders.
|
||||
/// Called when user wants to paste the files/folders. Bool is for cutting.
|
||||
/// </summary>
|
||||
public event Action<string[]> OnPaste;
|
||||
public event Action<string[], bool> OnPaste;
|
||||
|
||||
/// <summary>
|
||||
/// Called when user wants to duplicate the item(s).
|
||||
@@ -210,6 +212,12 @@ namespace FlaxEditor.Content.GUI
|
||||
}),
|
||||
new InputActionsContainer.Binding(options => options.Copy, Copy),
|
||||
new InputActionsContainer.Binding(options => options.Paste, Paste),
|
||||
new InputActionsContainer.Binding(options => options.Cut, Cut),
|
||||
new InputActionsContainer.Binding(options => options.Undo, () =>
|
||||
{
|
||||
if (_isCutting)
|
||||
UpdateContentItemCut(false);
|
||||
}),
|
||||
new InputActionsContainer.Binding(options => options.Duplicate, Duplicate),
|
||||
});
|
||||
}
|
||||
@@ -462,6 +470,7 @@ namespace FlaxEditor.Content.GUI
|
||||
/// </summary>
|
||||
public void Duplicate()
|
||||
{
|
||||
UpdateContentItemCut(false);
|
||||
OnDuplicate?.Invoke(_selection);
|
||||
}
|
||||
|
||||
@@ -475,6 +484,7 @@ namespace FlaxEditor.Content.GUI
|
||||
|
||||
var files = _selection.ConvertAll(x => x.Path).ToArray();
|
||||
Clipboard.Files = files;
|
||||
UpdateContentItemCut(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -496,7 +506,36 @@ namespace FlaxEditor.Content.GUI
|
||||
if (files == null || files.Length == 0)
|
||||
return;
|
||||
|
||||
OnPaste?.Invoke(files);
|
||||
OnPaste?.Invoke(files, _isCutting);
|
||||
UpdateContentItemCut(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cuts the items.
|
||||
/// </summary>
|
||||
public void Cut()
|
||||
{
|
||||
Copy();
|
||||
UpdateContentItemCut(true);
|
||||
}
|
||||
|
||||
private void UpdateContentItemCut(bool cut)
|
||||
{
|
||||
_isCutting = cut;
|
||||
|
||||
// Add selection to cut list
|
||||
if (cut)
|
||||
_cutItems.AddRange(_selection);
|
||||
|
||||
// Update item with if it is being cut.
|
||||
foreach (var item in _cutItems)
|
||||
{
|
||||
item.IsBeingCut = cut;
|
||||
}
|
||||
|
||||
// Clean up cut items
|
||||
if (!cut)
|
||||
_cutItems.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -58,10 +58,10 @@ namespace FlaxEngine.Tools
|
||||
FieldInfo[] fields = typeof(CustomMaxSizes).GetFields();
|
||||
for (int i = 0; i < fields.Length; i++)
|
||||
{
|
||||
var field = fields[i];
|
||||
if (field.Name.Equals("value__"))
|
||||
var @field = fields[i];
|
||||
if (@field.Name.Equals("value__"))
|
||||
continue;
|
||||
if (value == (int)field.GetRawConstantValue())
|
||||
if (value == (int)@field.GetRawConstantValue())
|
||||
return (CustomMaxSizes)value;
|
||||
}
|
||||
return CustomMaxSizes._8192;
|
||||
|
||||
@@ -182,6 +182,11 @@ namespace FlaxEditor.Content
|
||||
/// </summary>
|
||||
public const int DefaultHeight = (DefaultThumbnailSize + 2 * DefaultMarginSize + DefaultTextHeight);
|
||||
|
||||
/// <summary>
|
||||
/// Whether the item is being but.
|
||||
/// </summary>
|
||||
public bool IsBeingCut;
|
||||
|
||||
private ContentFolder _parentFolder;
|
||||
|
||||
private bool _isMouseDown;
|
||||
@@ -747,6 +752,12 @@ namespace FlaxEditor.Content
|
||||
Render2D.PushClip(ref textRect);
|
||||
Render2D.DrawText(style.FontMedium, ShowFileExtension || view.ShowFileExtensions ? FileName : ShortName, textRect, style.Foreground, nameAlignment, TextAlignment.Center, TextWrapping.WrapWords, 1f, 0.95f);
|
||||
Render2D.PopClip();
|
||||
|
||||
if (IsBeingCut)
|
||||
{
|
||||
var color = style.LightBackground.AlphaMultiplied(0.5f);
|
||||
Render2D.FillRectangle(clientRect, color);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -100,12 +100,16 @@ namespace FlaxEditor.Content
|
||||
/// <inheritdoc />
|
||||
public object GetValue(object obj)
|
||||
{
|
||||
if (!_type.Asset)
|
||||
throw new TargetException("Missing Visual Script asset.");
|
||||
return _type.Asset.GetScriptInstanceParameterValue(_parameter.Name, (Object)obj);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void SetValue(object obj, object value)
|
||||
{
|
||||
if (!_type.Asset)
|
||||
throw new TargetException("Missing Visual Script asset.");
|
||||
_type.Asset.SetScriptInstanceParameterValue(_parameter.Name, (Object)obj, value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -166,6 +166,18 @@ namespace FlaxEditor.Content
|
||||
/// <inheritdoc />
|
||||
public override string Name { get; } = Utilities.Utils.GetPropertyNameUI(typeof(T).Name);
|
||||
|
||||
private SpriteHandle _thumbnail;
|
||||
|
||||
public SpawnableJsonAssetProxy()
|
||||
{
|
||||
_thumbnail = SpriteHandle.Invalid;
|
||||
}
|
||||
|
||||
public SpawnableJsonAssetProxy(SpriteHandle thumbnail)
|
||||
{
|
||||
_thumbnail = thumbnail;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanCreate(ContentFolder targetLocation)
|
||||
{
|
||||
@@ -177,6 +189,12 @@ namespace FlaxEditor.Content
|
||||
{
|
||||
Editor.SaveJsonAsset(outputPath, new T());
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override AssetItem ConstructItem(string path, string typeName, ref Guid id)
|
||||
{
|
||||
return _thumbnail.IsValid ? new JsonAssetItem(path, id, typeName, _thumbnail) : base.ConstructItem(path, typeName, ref id);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string TypeName { get; } = typeof(T).FullName;
|
||||
|
||||
@@ -365,7 +365,7 @@ bool AndroidPlatformTools::OnPostProcess(CookingData& data)
|
||||
Platform::CreateProcess(procSettings);
|
||||
}
|
||||
#endif
|
||||
const bool distributionPackage = buildSettings->ForDistribution;
|
||||
const bool distributionPackage = buildSettings->ForDistribution || data.Configuration == BuildConfiguration::Release;
|
||||
{
|
||||
CreateProcessSettings procSettings;
|
||||
procSettings.FileName = String::Format(TEXT("\"{0}\" {1}"), data.OriginalOutputPath / gradlew, distributionPackage ? TEXT("assemble") : TEXT("assembleDebug"));
|
||||
|
||||
@@ -111,6 +111,11 @@ namespace FlaxEditor.CustomEditors
|
||||
/// </summary>
|
||||
public PropertyNameLabel LinkedLabel;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the layout for this editor. Used to calculate bounds.
|
||||
/// </summary>
|
||||
public LayoutElementsContainer Layout => _layout;
|
||||
|
||||
internal virtual void Initialize(CustomEditorPresenter presenter, LayoutElementsContainer layout, ValueContainer values)
|
||||
{
|
||||
_layout = layout;
|
||||
@@ -659,7 +664,7 @@ namespace FlaxEditor.CustomEditors
|
||||
}
|
||||
}
|
||||
|
||||
if (obj == null || Values.Type.IsInstanceOfType(obj))
|
||||
if ((obj == null && !Values.Type.IsValueType) || Values.Type.IsInstanceOfType(obj))
|
||||
{
|
||||
result = obj;
|
||||
return true;
|
||||
@@ -671,20 +676,7 @@ namespace FlaxEditor.CustomEditors
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether can paste value from the system clipboard to the property value container.
|
||||
/// </summary>
|
||||
public bool CanPaste
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
return GetClipboardObject(out _, false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
public bool CanPaste => !string.IsNullOrEmpty(Clipboard.Text);
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value from the system clipboard.
|
||||
|
||||
@@ -52,13 +52,18 @@ namespace FlaxEditor.CustomEditors
|
||||
// Check if use provided editor
|
||||
if (overrideEditor != null)
|
||||
return overrideEditor;
|
||||
ScriptType targetType = values.Type;
|
||||
|
||||
// Special case if property is a pure object type and all values are the same type
|
||||
if (values.Type.Type == typeof(object) && values.Count > 0 && values[0] != null && !values.HasDifferentTypes)
|
||||
if (targetType.Type == typeof(object) && values.Count > 0 && values[0] != null && !values.HasDifferentTypes)
|
||||
return CreateEditor(TypeUtils.GetObjectType(values[0]), canUseRefPicker);
|
||||
|
||||
// Special case if property is interface but the value is implemented as Scripting Object that should use reference picker
|
||||
if (targetType.IsInterface && canUseRefPicker && values.Count > 0 && values[0] is FlaxEngine.Object)
|
||||
return new DummyEditor();
|
||||
|
||||
// Use editor for the property type
|
||||
return CreateEditor(values.Type, canUseRefPicker);
|
||||
return CreateEditor(targetType, canUseRefPicker);
|
||||
}
|
||||
|
||||
internal static CustomEditor CreateEditor(ScriptType targetType, bool canUseRefPicker = true)
|
||||
|
||||
@@ -67,19 +67,35 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
// Use default prefab instance as a reference for the editor
|
||||
Values.SetReferenceValue(prefabInstance);
|
||||
|
||||
// Add some UI
|
||||
var panel = layout.CustomContainer<UniformGridPanel>();
|
||||
panel.CustomControl.Height = 20.0f;
|
||||
panel.CustomControl.SlotsVertically = 1;
|
||||
panel.CustomControl.SlotsHorizontally = 2;
|
||||
if (Presenter == Editor.Instance.Windows.PropertiesWin.Presenter)
|
||||
{
|
||||
// Add some UI
|
||||
var panel = layout.CustomContainer<UniformGridPanel>();
|
||||
panel.CustomControl.Height = 20.0f;
|
||||
panel.CustomControl.SlotsVertically = 1;
|
||||
panel.CustomControl.SlotsHorizontally = 3;
|
||||
|
||||
// Selecting actor prefab asset
|
||||
var selectPrefab = panel.Button("Select Prefab");
|
||||
selectPrefab.Button.Clicked += () =>
|
||||
{
|
||||
Editor.Instance.Windows.ContentWin.ClearItemsSearch();
|
||||
Editor.Instance.Windows.ContentWin.Select(prefab);
|
||||
};
|
||||
|
||||
// Selecting actor prefab asset
|
||||
var selectPrefab = panel.Button("Select Prefab");
|
||||
selectPrefab.Button.Clicked += () => Editor.Instance.Windows.ContentWin.Select(prefab);
|
||||
// Edit selected prefab asset
|
||||
var editPrefab = panel.Button("Edit Prefab");
|
||||
editPrefab.Button.Clicked += () =>
|
||||
{
|
||||
Editor.Instance.Windows.ContentWin.ClearItemsSearch();
|
||||
Editor.Instance.Windows.ContentWin.Select(prefab);
|
||||
Editor.Instance.Windows.ContentWin.Open(Editor.Instance.Windows.ContentWin.View.Selection[0]);
|
||||
};
|
||||
|
||||
// Viewing changes applied to this actor
|
||||
var viewChanges = panel.Button("View Changes");
|
||||
viewChanges.Button.Clicked += () => ViewChanges(viewChanges.Button, new Float2(0.0f, 20.0f));
|
||||
// Viewing changes applied to this actor
|
||||
var viewChanges = panel.Button("View Changes");
|
||||
viewChanges.Button.Clicked += () => ViewChanges(viewChanges.Button, new Float2(0.0f, 20.0f));
|
||||
}
|
||||
|
||||
// Link event to update editor on prefab apply
|
||||
_linkedPrefabId = prefab.ID;
|
||||
|
||||
@@ -38,15 +38,15 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
_gizmoMode = new ClothPaintingGizmoMode();
|
||||
|
||||
var projectCache = Editor.Instance.ProjectCache;
|
||||
if (projectCache.TryGetCustomData("ClothGizmoPaintValue", out var cachedPaintValue))
|
||||
if (projectCache.TryGetCustomData("ClothGizmoPaintValue", out string cachedPaintValue))
|
||||
_gizmoMode.PaintValue = JsonSerializer.Deserialize<float>(cachedPaintValue);
|
||||
if (projectCache.TryGetCustomData("ClothGizmoContinuousPaint", out var cachedContinuousPaint))
|
||||
if (projectCache.TryGetCustomData("ClothGizmoContinuousPaint", out string cachedContinuousPaint))
|
||||
_gizmoMode.ContinuousPaint = JsonSerializer.Deserialize<bool>(cachedContinuousPaint);
|
||||
if (projectCache.TryGetCustomData("ClothGizmoBrushFalloff", out var cachedBrushFalloff))
|
||||
if (projectCache.TryGetCustomData("ClothGizmoBrushFalloff", out string cachedBrushFalloff))
|
||||
_gizmoMode.BrushFalloff = JsonSerializer.Deserialize<float>(cachedBrushFalloff);
|
||||
if (projectCache.TryGetCustomData("ClothGizmoBrushSize", out var cachedBrushSize))
|
||||
if (projectCache.TryGetCustomData("ClothGizmoBrushSize", out string cachedBrushSize))
|
||||
_gizmoMode.BrushSize = JsonSerializer.Deserialize<float>(cachedBrushSize);
|
||||
if (projectCache.TryGetCustomData("ClothGizmoBrushStrength", out var cachedBrushStrength))
|
||||
if (projectCache.TryGetCustomData("ClothGizmoBrushStrength", out string cachedBrushStrength))
|
||||
_gizmoMode.BrushStrength = JsonSerializer.Deserialize<float>(cachedBrushStrength);
|
||||
|
||||
gizmos.AddMode(_gizmoMode);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using FlaxEditor.Content.Settings;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
@@ -12,7 +13,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
[CustomEditor(typeof(LayersMask)), DefaultEditor]
|
||||
internal class LayersMaskEditor : CustomEditor
|
||||
{
|
||||
private CheckBox[] _checkBoxes;
|
||||
private List<CheckBox> _checkBoxes;
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
@@ -24,16 +25,18 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
return;
|
||||
}
|
||||
|
||||
_checkBoxes = new CheckBox[layers.Length];
|
||||
_checkBoxes = new List<CheckBox>();
|
||||
for (int i = 0; i < layers.Length; i++)
|
||||
{
|
||||
var layer = layers[i];
|
||||
var property = layout.AddPropertyItem(layer);
|
||||
if (string.IsNullOrEmpty(layer))
|
||||
continue;
|
||||
var property = layout.AddPropertyItem($"{i}: {layer}");
|
||||
var checkbox = property.Checkbox().CheckBox;
|
||||
UpdateCheckbox(checkbox, i);
|
||||
checkbox.Tag = i;
|
||||
checkbox.StateChanged += OnCheckboxStateChanged;
|
||||
_checkBoxes[i] = checkbox;
|
||||
_checkBoxes.Add(checkbox);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,9 +53,9 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
if (_checkBoxes != null)
|
||||
{
|
||||
for (int i = 0; i < _checkBoxes.Length; i++)
|
||||
for (int i = 0; i < _checkBoxes.Count; i++)
|
||||
{
|
||||
UpdateCheckbox(_checkBoxes[i], i);
|
||||
UpdateCheckbox(_checkBoxes[i], (int)_checkBoxes[i].Tag);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -880,6 +880,13 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
|
||||
group.Panel.HeaderTextMargin = new Margin(scriptDrag.Right - 12, 15, 2, 2);
|
||||
group.Object(values, editor);
|
||||
// Remove drop down arrows and containment lines if no objects in the group
|
||||
if (group.Children.Count == 0)
|
||||
{
|
||||
group.Panel.ArrowImageOpened = null;
|
||||
group.Panel.ArrowImageClosed = null;
|
||||
group.Panel.EnableContainmentLines = false;
|
||||
}
|
||||
|
||||
// Scripts arrange bar
|
||||
dragBar = layout.Custom<ScriptArrangeBar>();
|
||||
|
||||
@@ -456,14 +456,57 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
|
||||
for (int i = 0; i < layout.Children.Count; i++)
|
||||
{
|
||||
if (layout.Children[i] is GroupElement group && group.Panel.HeaderText == "Transform")
|
||||
if (layout.Children[i] is GroupElement group && group.Panel.HeaderText.Equals("Transform", StringComparison.Ordinal))
|
||||
{
|
||||
VerticalPanelElement mainHor = VerticalPanelWithoutMargin(group);
|
||||
CreateTransformElements(mainHor, ValuesTypes);
|
||||
group.ContainerControl.ChangeChildIndex(mainHor.Control, 0);
|
||||
layout.Children.Remove(group);
|
||||
layout.ContainerControl.Children.Remove(group.Panel);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Setup transform
|
||||
if (Presenter is LayoutElementsContainer l)
|
||||
{
|
||||
for (int i = 0; i < l.Children.Count; i++)
|
||||
{
|
||||
if (l.Children[i] is GroupElement g && g.Panel.HeaderText.Equals("Transform", StringComparison.Ordinal))
|
||||
{
|
||||
l.Children.Remove(g);
|
||||
l.ContainerControl.Children.Remove(g.Panel);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var transformGroup = l.Group("Transform");
|
||||
VerticalPanelElement mainHor = VerticalPanelWithoutMargin(transformGroup);
|
||||
CreateTransformElements(mainHor, ValuesTypes);
|
||||
|
||||
ScriptMemberInfo scaleInfo = ValuesTypes[0].GetProperty("Scale");
|
||||
ItemInfo scaleItem = new ItemInfo(scaleInfo);
|
||||
transformGroup.Property("Scale", scaleItem.GetValues(Values));
|
||||
|
||||
ScriptMemberInfo pivotInfo = ValuesTypes[0].GetProperty("Pivot");
|
||||
ItemInfo pivotItem = new ItemInfo(pivotInfo);
|
||||
transformGroup.Property("Pivot", pivotItem.GetValues(Values));
|
||||
|
||||
ScriptMemberInfo shearInfo = ValuesTypes[0].GetProperty("Shear");
|
||||
ItemInfo shearItem = new ItemInfo(shearInfo);
|
||||
transformGroup.Property("Shear", shearItem.GetValues(Values));
|
||||
|
||||
ScriptMemberInfo rotationInfo = ValuesTypes[0].GetProperty("Rotation");
|
||||
ItemInfo rotationItem = new ItemInfo(rotationInfo);
|
||||
transformGroup.Property("Rotation", rotationItem.GetValues(Values));
|
||||
|
||||
// Get position of general tab
|
||||
for (int i = 0; i < l.Children.Count; i++)
|
||||
{
|
||||
if (l.Children[i] is GroupElement g && g.Panel.HeaderText.Equals("General", StringComparison.Ordinal) && i + 1 <= l.Children.Count)
|
||||
{
|
||||
Presenter.ContainerControl.ChangeChildIndex(transformGroup.Control, i + 1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CreateTransformElements(LayoutElementsContainer main, ScriptType[] valueTypes)
|
||||
@@ -645,7 +688,7 @@ namespace FlaxEditor.CustomEditors.Dedicated
|
||||
{
|
||||
var grid = UniformGridTwoByOne(el);
|
||||
grid.CustomControl.SlotPadding = new Margin(5, 5, 1, 1);
|
||||
var label = grid.Label(text);
|
||||
var label = grid.Label(text, TextAlignment.Far);
|
||||
var editor = grid.Object(values);
|
||||
if (editor is FloatEditor floatEditor && floatEditor.Element is FloatValueElement floatEditorElement)
|
||||
{
|
||||
|
||||
@@ -41,6 +41,13 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
base.Initialize(layout);
|
||||
|
||||
if (XElement.ValueBox.Parent is UniformGridPanel ug)
|
||||
{
|
||||
ug.Height += 2;
|
||||
ug.SlotSpacing = new Float2(4);
|
||||
ug.SlotPadding = new Margin(0, 0, 1, 1);
|
||||
}
|
||||
|
||||
// Override colors
|
||||
var back = FlaxEngine.GUI.Style.Current.TextBoxBackground;
|
||||
@@ -66,6 +73,13 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
base.Initialize(layout);
|
||||
|
||||
if (XElement.ValueBox.Parent is UniformGridPanel ug)
|
||||
{
|
||||
ug.Height += 2;
|
||||
ug.SlotSpacing = new Float2(4);
|
||||
ug.SlotPadding = new Margin(0, 0, 1, 1);
|
||||
}
|
||||
|
||||
// Override colors
|
||||
var back = FlaxEngine.GUI.Style.Current.TextBoxBackground;
|
||||
@@ -122,6 +136,13 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
menu.AddButton("Link", ToggleLink).LinkTooltip("Links scale components for uniform scaling");
|
||||
};
|
||||
}
|
||||
|
||||
if (XElement.ValueBox.Parent is UniformGridPanel ug)
|
||||
{
|
||||
ug.Height += 2;
|
||||
ug.SlotSpacing = new Float2(4);
|
||||
ug.SlotPadding = new Margin(0, 0, 1, 1);
|
||||
}
|
||||
|
||||
// Override colors
|
||||
var back = FlaxEngine.GUI.Style.Current.TextBoxBackground;
|
||||
|
||||
@@ -38,6 +38,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
/// </summary>
|
||||
public readonly int Index;
|
||||
|
||||
private Rectangle _arrangeButtonRect;
|
||||
private bool _arrangeButtonInUse;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="CollectionItemLabel"/> class.
|
||||
/// </summary>
|
||||
@@ -50,6 +53,12 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
Index = index;
|
||||
|
||||
SetupContextMenu += OnSetupContextMenu;
|
||||
_arrangeButtonRect = new Rectangle(2, 3, 12, 12);
|
||||
|
||||
// Extend margin of the label to support a dragging handle.
|
||||
Margin m = Margin;
|
||||
m.Left += 16;
|
||||
Margin = m;
|
||||
}
|
||||
|
||||
private void OnSetupContextMenu(PropertyNameLabel label, ContextMenu menu, CustomEditor linkedEditor)
|
||||
@@ -57,17 +66,119 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
menu.ItemsContainer.RemoveChildren();
|
||||
|
||||
menu.AddButton("Copy", linkedEditor.Copy);
|
||||
var paste = menu.AddButton("Paste", linkedEditor.Paste);
|
||||
paste.Enabled = linkedEditor.CanPaste;
|
||||
var b = menu.AddButton("Paste", linkedEditor.Paste);
|
||||
b.Enabled = linkedEditor.CanPaste && !Editor._readOnly;
|
||||
|
||||
menu.AddSeparator();
|
||||
var moveUpButton = menu.AddButton("Move up", OnMoveUpClicked);
|
||||
moveUpButton.Enabled = Index > 0;
|
||||
b = menu.AddButton("Move up", OnMoveUpClicked);
|
||||
b.Enabled = Index > 0 && !Editor._readOnly;
|
||||
|
||||
var moveDownButton = menu.AddButton("Move down", OnMoveDownClicked);
|
||||
moveDownButton.Enabled = Index + 1 < Editor.Count;
|
||||
b = menu.AddButton("Move down", OnMoveDownClicked);
|
||||
b.Enabled = Index + 1 < Editor.Count && !Editor._readOnly;
|
||||
|
||||
b = menu.AddButton("Remove", OnRemoveClicked);
|
||||
b.Enabled = !Editor._readOnly;
|
||||
}
|
||||
|
||||
menu.AddButton("Remove", OnRemoveClicked);
|
||||
/// <inheritdoc />
|
||||
public override void OnEndMouseCapture()
|
||||
{
|
||||
base.OnEndMouseCapture();
|
||||
|
||||
_arrangeButtonInUse = false;
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
{
|
||||
base.Draw();
|
||||
var style = FlaxEngine.GUI.Style.Current;
|
||||
|
||||
var mousePosition = PointFromScreen(Input.MouseScreenPosition);
|
||||
var dragBarColor = _arrangeButtonRect.Contains(mousePosition) ? style.Foreground : style.ForegroundGrey;
|
||||
Render2D.DrawSprite(FlaxEditor.Editor.Instance.Icons.DragBar12, _arrangeButtonRect, _arrangeButtonInUse ? Color.Orange : dragBarColor);
|
||||
if (_arrangeButtonInUse && ArrangeAreaCheck(out _, out var arrangeTargetRect))
|
||||
{
|
||||
Render2D.FillRectangle(arrangeTargetRect, style.Selection);
|
||||
}
|
||||
}
|
||||
|
||||
private bool ArrangeAreaCheck(out int index, out Rectangle rect)
|
||||
{
|
||||
var child = Editor.ChildrenEditors[0];
|
||||
var container = child.Layout.ContainerControl;
|
||||
var mousePosition = container.PointFromScreen(Input.MouseScreenPosition);
|
||||
var barSidesExtend = 20.0f;
|
||||
var barHeight = 5.0f;
|
||||
var barCheckAreaHeight = 40.0f;
|
||||
var pos = mousePosition.Y + barCheckAreaHeight * 0.5f;
|
||||
|
||||
for (int i = 0; i < container.Children.Count / 2; i++)
|
||||
{
|
||||
var containerChild = container.Children[i * 2]; // times 2 to skip the value editor
|
||||
if (Mathf.IsInRange(pos, containerChild.Top, containerChild.Top + barCheckAreaHeight) || (i == 0 && pos < containerChild.Top))
|
||||
{
|
||||
index = i;
|
||||
var p1 = containerChild.UpperLeft;
|
||||
rect = new Rectangle(PointFromParent(p1) - new Float2(barSidesExtend * 0.5f, barHeight * 0.5f), Width + barSidesExtend, barHeight);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
var p2 = container.Children[((container.Children.Count / 2) - 1) * 2].BottomLeft;
|
||||
if (pos > p2.Y)
|
||||
{
|
||||
index = (container.Children.Count / 2) - 1;
|
||||
rect = new Rectangle(PointFromParent(p2) - new Float2(barSidesExtend * 0.5f, barHeight * 0.5f), Width + barSidesExtend, barHeight);
|
||||
return true;
|
||||
}
|
||||
|
||||
index = -1;
|
||||
rect = Rectangle.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left && _arrangeButtonRect.Contains(ref location))
|
||||
{
|
||||
_arrangeButtonInUse = true;
|
||||
Focus();
|
||||
StartMouseCapture();
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnMouseDown(location, button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left && _arrangeButtonInUse)
|
||||
{
|
||||
_arrangeButtonInUse = false;
|
||||
EndMouseCapture();
|
||||
if (ArrangeAreaCheck(out var index, out _))
|
||||
{
|
||||
Editor.Shift(Index, index);
|
||||
}
|
||||
}
|
||||
|
||||
return base.OnMouseUp(location, button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnLostFocus()
|
||||
{
|
||||
if (_arrangeButtonInUse)
|
||||
{
|
||||
_arrangeButtonInUse = false;
|
||||
EndMouseCapture();
|
||||
}
|
||||
|
||||
base.OnLostFocus();
|
||||
}
|
||||
|
||||
private void OnMoveUpClicked()
|
||||
@@ -105,6 +216,9 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
|
||||
private bool _canReorder = true;
|
||||
|
||||
private Rectangle _arrangeButtonRect;
|
||||
private bool _arrangeButtonInUse;
|
||||
|
||||
public void Setup(CollectionEditor editor, int index, bool canReorder = true)
|
||||
{
|
||||
HeaderHeight = 18;
|
||||
@@ -122,10 +236,92 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
MouseButtonRightClicked += OnMouseButtonRightClicked;
|
||||
if (_canReorder)
|
||||
{
|
||||
// TODO: Drag drop
|
||||
HeaderTextMargin = new Margin(18, 0, 0, 0);
|
||||
_arrangeButtonRect = new Rectangle(16, 3, 12, 12);
|
||||
}
|
||||
}
|
||||
|
||||
private bool ArrangeAreaCheck(out int index, out Rectangle rect)
|
||||
{
|
||||
var container = Parent;
|
||||
var mousePosition = container.PointFromScreen(Input.MouseScreenPosition);
|
||||
var barSidesExtend = 20.0f;
|
||||
var barHeight = 5.0f;
|
||||
var barCheckAreaHeight = 40.0f;
|
||||
var pos = mousePosition.Y + barCheckAreaHeight * 0.5f;
|
||||
|
||||
for (int i = 0; i < (container.Children.Count + 1) / 2; i++) // Add 1 to pretend there is a spacer at the end.
|
||||
{
|
||||
var containerChild = container.Children[i * 2]; // times 2 to skip the value editor
|
||||
if (Mathf.IsInRange(pos, containerChild.Top, containerChild.Top + barCheckAreaHeight) || (i == 0 && pos < containerChild.Top))
|
||||
{
|
||||
index = i;
|
||||
var p1 = containerChild.UpperLeft;
|
||||
rect = new Rectangle(PointFromParent(p1) - new Float2(barSidesExtend * 0.5f, barHeight * 0.5f), Width + barSidesExtend, barHeight);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
var p2 = container.Children[container.Children.Count - 1].BottomLeft;
|
||||
if (pos > p2.Y)
|
||||
{
|
||||
index = ((container.Children.Count + 1) / 2) - 1;
|
||||
rect = new Rectangle(PointFromParent(p2) - new Float2(barSidesExtend * 0.5f, barHeight * 0.5f), Width + barSidesExtend, barHeight);
|
||||
return true;
|
||||
}
|
||||
|
||||
index = -1;
|
||||
rect = Rectangle.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Draw()
|
||||
{
|
||||
base.Draw();
|
||||
if (_canReorder)
|
||||
{
|
||||
var style = FlaxEngine.GUI.Style.Current;
|
||||
|
||||
var mousePosition = PointFromScreen(Input.MouseScreenPosition);
|
||||
var dragBarColor = _arrangeButtonRect.Contains(mousePosition) ? style.Foreground : style.ForegroundGrey;
|
||||
Render2D.DrawSprite(FlaxEditor.Editor.Instance.Icons.DragBar12, _arrangeButtonRect, _arrangeButtonInUse ? Color.Orange : dragBarColor);
|
||||
if (_arrangeButtonInUse && ArrangeAreaCheck(out _, out var arrangeTargetRect))
|
||||
{
|
||||
Render2D.FillRectangle(arrangeTargetRect, style.Selection);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left && _arrangeButtonRect.Contains(ref location))
|
||||
{
|
||||
_arrangeButtonInUse = true;
|
||||
Focus();
|
||||
StartMouseCapture();
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnMouseDown(location, button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left && _arrangeButtonInUse)
|
||||
{
|
||||
_arrangeButtonInUse = false;
|
||||
EndMouseCapture();
|
||||
if (ArrangeAreaCheck(out var index, out _))
|
||||
{
|
||||
Editor.Shift(Index, index);
|
||||
}
|
||||
}
|
||||
|
||||
return base.OnMouseUp(location, button);
|
||||
}
|
||||
|
||||
private void OnMouseButtonRightClicked(DropPanel panel, Float2 location)
|
||||
{
|
||||
if (LinkedEditor == null)
|
||||
@@ -177,6 +373,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
private IntValueBox _sizeBox;
|
||||
private Color _background;
|
||||
private int _elementsCount, _minCount, _maxCount;
|
||||
private bool _readOnly;
|
||||
private bool _canResize;
|
||||
private bool _canReorderItems;
|
||||
private CollectionAttribute.DisplayType _displayType;
|
||||
@@ -209,6 +406,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
return;
|
||||
|
||||
var size = Count;
|
||||
_readOnly = false;
|
||||
_canResize = true;
|
||||
_canReorderItems = true;
|
||||
_minCount = 0;
|
||||
@@ -224,7 +422,8 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
var collection = (CollectionAttribute)attributes?.FirstOrDefault(x => x is CollectionAttribute);
|
||||
if (collection != null)
|
||||
{
|
||||
_canResize = !collection.ReadOnly;
|
||||
_canResize = collection.CanResize;
|
||||
_readOnly = collection.ReadOnly;
|
||||
_minCount = collection.MinCount;
|
||||
_maxCount = collection.MaxCount;
|
||||
_canReorderItems = collection.CanReorderItems;
|
||||
@@ -235,6 +434,12 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
spacing = collection.Spacing;
|
||||
_displayType = collection.Display;
|
||||
}
|
||||
if (attributes != null && attributes.Any(x => x is ReadOnlyAttribute))
|
||||
{
|
||||
_readOnly = true;
|
||||
_canResize = false;
|
||||
_canReorderItems = false;
|
||||
}
|
||||
if (_maxCount == 0)
|
||||
_maxCount = ushort.MaxValue;
|
||||
_canResize &= _minCount < _maxCount;
|
||||
@@ -243,8 +448,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
dragArea.CustomControl.Editor = this;
|
||||
dragArea.CustomControl.ElementType = ElementType;
|
||||
|
||||
// Check for the AssetReferenceAttribute. In JSON assets, it can be used to filter
|
||||
// which scripts can be dragged over and dropped on this collection editor.
|
||||
// Check for the AssetReferenceAttribute. In JSON assets, it can be used to filter which scripts can be dragged over and dropped on this collection editor
|
||||
var assetReference = (AssetReferenceAttribute)attributes?.FirstOrDefault(x => x is AssetReferenceAttribute);
|
||||
if (assetReference != null)
|
||||
{
|
||||
@@ -315,7 +519,6 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
(elementType.GetProperties().Length == 1 && elementType.GetFields().Length == 0) ||
|
||||
elementType.Equals(new ScriptType(typeof(JsonAsset))) ||
|
||||
elementType.Equals(new ScriptType(typeof(SettingsBase)));
|
||||
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
// Apply spacing
|
||||
@@ -333,6 +536,8 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
var property = panel.AddPropertyItem(itemLabel);
|
||||
var itemLayout = (LayoutElementsContainer)property;
|
||||
itemLabel.LinkedEditor = itemLayout.Object(new ListValueContainer(elementType, i, Values, attributes), overrideEditor);
|
||||
if (_readOnly && itemLayout.Children.Count > 0)
|
||||
GenericEditor.OnReadOnlyProperty(itemLayout);
|
||||
}
|
||||
else if (_displayType == CollectionAttribute.DisplayType.Header || (_displayType == CollectionAttribute.DisplayType.Default && !single))
|
||||
{
|
||||
@@ -340,13 +545,15 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
cdp.CustomControl.Setup(this, i, _canReorderItems);
|
||||
var itemLayout = cdp.VerticalPanel();
|
||||
cdp.CustomControl.LinkedEditor = itemLayout.Object(new ListValueContainer(elementType, i, Values, attributes), overrideEditor);
|
||||
if (_readOnly && itemLayout.Children.Count > 0)
|
||||
GenericEditor.OnReadOnlyProperty(itemLayout);
|
||||
}
|
||||
}
|
||||
}
|
||||
_elementsCount = size;
|
||||
|
||||
// Add/Remove buttons
|
||||
if (_canResize)
|
||||
if (_canResize && !_readOnly)
|
||||
{
|
||||
var panel = dragArea.HorizontalPanel();
|
||||
panel.Panel.Size = new Float2(0, 20);
|
||||
@@ -427,6 +634,39 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
SetValue(cloned);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shifts the specified item at the given index and moves it through the list to the other item. It supports undo.
|
||||
/// </summary>
|
||||
/// <param name="srcIndex">Index of the source item.</param>
|
||||
/// <param name="dstIndex">Index of the destination to move to.</param>
|
||||
private void Shift(int srcIndex, int dstIndex)
|
||||
{
|
||||
if (IsSetBlocked)
|
||||
return;
|
||||
|
||||
var cloned = CloneValues();
|
||||
if (dstIndex > srcIndex)
|
||||
{
|
||||
for (int i = srcIndex; i < dstIndex; i++)
|
||||
{
|
||||
var tmp = cloned[i + 1];
|
||||
cloned[i + 1] = cloned[i];
|
||||
cloned[i] = tmp;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = srcIndex; i > dstIndex; i--)
|
||||
{
|
||||
var tmp = cloned[i - 1];
|
||||
cloned[i - 1] = cloned[i];
|
||||
cloned[i] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
SetValue(cloned);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the item at the specified index. It supports undo.
|
||||
/// </summary>
|
||||
|
||||
@@ -131,7 +131,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDoubleClick(Float2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left)
|
||||
if (button == MouseButton.Left && _editor._canEditKeys)
|
||||
{
|
||||
OnEditClicked(null);
|
||||
return true;
|
||||
@@ -189,6 +189,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
var collection = (CollectionAttribute)attributes?.FirstOrDefault(x => x is CollectionAttribute);
|
||||
if (collection != null)
|
||||
{
|
||||
_canEditKeys &= collection.CanReorderItems;
|
||||
_readOnly = collection.ReadOnly;
|
||||
_notNullItems = collection.NotNullItems;
|
||||
if (collection.BackgroundColor.HasValue)
|
||||
@@ -197,6 +198,11 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
spacing = collection.Spacing;
|
||||
_displayType = collection.Display;
|
||||
}
|
||||
if (attributes != null && attributes.Any(x => x is ReadOnlyAttribute))
|
||||
{
|
||||
_readOnly = true;
|
||||
_canEditKeys = false;
|
||||
}
|
||||
|
||||
// Size
|
||||
if (layout.ContainerControl is DropPanel dropPanel)
|
||||
@@ -239,14 +245,6 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
var keysEnumerable = ((IDictionary)Values[0]).Keys.OfType<object>();
|
||||
var keys = keysEnumerable as object[] ?? keysEnumerable.ToArray();
|
||||
var valuesType = new ScriptType(valueType);
|
||||
|
||||
bool single = valuesType.IsPrimitive ||
|
||||
valuesType.Equals(new ScriptType(typeof(string))) ||
|
||||
valuesType.IsEnum ||
|
||||
(valuesType.GetFields().Length == 1 && valuesType.GetProperties().Length == 0) ||
|
||||
(valuesType.GetProperties().Length == 1 && valuesType.GetFields().Length == 0) ||
|
||||
valuesType.Equals(new ScriptType(typeof(JsonAsset))) ||
|
||||
valuesType.Equals(new ScriptType(typeof(SettingsBase)));
|
||||
|
||||
// Use separate layout cells for each collection items to improve layout updates for them in separation
|
||||
var useSharedLayout = valueType.IsPrimitive || valueType.IsEnum;
|
||||
@@ -263,6 +261,8 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
var property = panel.AddPropertyItem(new DictionaryItemLabel(this, key));
|
||||
var itemLayout = useSharedLayout ? (LayoutElementsContainer)property : property.VerticalPanel();
|
||||
itemLayout.Object(new DictionaryValueContainer(valuesType, key, Values), overrideEditor);
|
||||
if (_readOnly && itemLayout.Children.Count > 0)
|
||||
GenericEditor.OnReadOnlyProperty(itemLayout);
|
||||
}
|
||||
}
|
||||
_elementsCount = size;
|
||||
|
||||
17
Source/Editor/CustomEditors/Editors/DummyEditor.cs
Normal file
17
Source/Editor/CustomEditors/Editors/DummyEditor.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
namespace FlaxEditor.CustomEditors.Editors
|
||||
{
|
||||
internal sealed class DummyEditor : CustomEditor
|
||||
{
|
||||
public override void Initialize(LayoutElementsContainer layout)
|
||||
{
|
||||
string valueName;
|
||||
if (Values.Count != 0 && Values[0] != null)
|
||||
valueName = Values[0].ToString();
|
||||
else
|
||||
valueName = "null";
|
||||
layout.Label($"{valueName} ({Values.Type})");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -208,7 +208,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
else
|
||||
{
|
||||
// Draw info
|
||||
Render2D.DrawText(style.FontMedium, "-", nameRect, isEnabled ? Color.OrangeRed : Color.DarkOrange, TextAlignment.Near, TextAlignment.Center);
|
||||
Render2D.DrawText(style.FontMedium, Type != null ? $"None ({Utilities.Utils.GetPropertyNameUI(Type.ToString())})" : "-", nameRect, isEnabled ? Color.OrangeRed : Color.DarkOrange, TextAlignment.Near, TextAlignment.Center);
|
||||
}
|
||||
|
||||
// Draw picker button
|
||||
|
||||
@@ -474,32 +474,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
}
|
||||
if (layout.Editors.Count != 0)
|
||||
{
|
||||
var sb = Clipboard.Text;
|
||||
if (!string.IsNullOrEmpty(sb))
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = JsonSerializer.Deserialize<string[]>(sb);
|
||||
if (data == null || data.Length != layout.Editors.Count)
|
||||
return false;
|
||||
for (var i = 0; i < layout.Editors.Count; i++)
|
||||
{
|
||||
Clipboard.Text = data[i];
|
||||
if (!layout.Editors[i].CanPaste)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Clipboard.Text = sb;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return !string.IsNullOrEmpty(Clipboard.Text);
|
||||
}
|
||||
if (layout.Children.Any(x => x is LayoutElementsContainer))
|
||||
{
|
||||
@@ -581,6 +556,43 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
return layout;
|
||||
}
|
||||
|
||||
internal static void OnReadOnlyProperty(LayoutElementsContainer itemLayout, int labelIndex = -1)
|
||||
{
|
||||
PropertiesListElement list = null;
|
||||
int firstChildControlIndex = 0;
|
||||
bool disableSingle = true;
|
||||
var control = itemLayout.Children[itemLayout.Children.Count - 1];
|
||||
if (control is GroupElement group && group.Children.Count > 0)
|
||||
{
|
||||
list = group.Children[0] as PropertiesListElement;
|
||||
disableSingle = false; // Disable all nested editors
|
||||
}
|
||||
else if (control is PropertiesListElement list1 && labelIndex != -1)
|
||||
{
|
||||
list = list1;
|
||||
firstChildControlIndex = list.Labels[labelIndex].FirstChildControlIndex;
|
||||
}
|
||||
else if (control?.Control != null)
|
||||
{
|
||||
control.Control.Enabled = false;
|
||||
}
|
||||
|
||||
if (list != null)
|
||||
{
|
||||
// Disable controls added to the editor
|
||||
var count = list.Properties.Children.Count;
|
||||
for (int j = firstChildControlIndex; j < count; j++)
|
||||
{
|
||||
var child = list.Properties.Children[j];
|
||||
if (disableSingle && child is PropertyNameLabel)
|
||||
break;
|
||||
|
||||
if (child != null)
|
||||
child.Enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Evaluate the <see cref="VisibleIfAttribute"/> cache for a given property item.
|
||||
/// </summary>
|
||||
@@ -660,35 +672,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
|
||||
if (item.IsReadOnly && itemLayout.Children.Count > 0)
|
||||
{
|
||||
PropertiesListElement list = null;
|
||||
int firstChildControlIndex = 0;
|
||||
bool disableSingle = true;
|
||||
var control = itemLayout.Children[itemLayout.Children.Count - 1];
|
||||
if (control is GroupElement group && group.Children.Count > 0)
|
||||
{
|
||||
list = group.Children[0] as PropertiesListElement;
|
||||
disableSingle = false; // Disable all nested editors
|
||||
}
|
||||
else if (control is PropertiesListElement list1)
|
||||
{
|
||||
list = list1;
|
||||
firstChildControlIndex = list.Labels[labelIndex].FirstChildControlIndex;
|
||||
}
|
||||
|
||||
if (list != null)
|
||||
{
|
||||
// Disable controls added to the editor
|
||||
var count = list.Properties.Children.Count;
|
||||
for (int j = firstChildControlIndex; j < count; j++)
|
||||
{
|
||||
var child = list.Properties.Children[j];
|
||||
if (disableSingle && child is PropertyNameLabel)
|
||||
break;
|
||||
|
||||
if (child != null)
|
||||
child.Enabled = false;
|
||||
}
|
||||
}
|
||||
OnReadOnlyProperty(itemLayout, labelIndex);
|
||||
}
|
||||
|
||||
EvaluateVisibleIf(itemLayout, item, labelIndex);
|
||||
|
||||
@@ -83,6 +83,22 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
_element.Value = asInt;
|
||||
else if (value is float asFloat)
|
||||
_element.Value = (int)asFloat;
|
||||
else if (value is double asDouble)
|
||||
_element.Value = (int)asDouble;
|
||||
else if (value is uint asUint)
|
||||
_element.Value = (int)asUint;
|
||||
else if (value is long asLong)
|
||||
_element.Value = (int)asLong;
|
||||
else if (value is ulong asULong)
|
||||
_element.Value = (int)asULong;
|
||||
else if (value is short asShort)
|
||||
_element.Value = asShort;
|
||||
else if (value is ushort asUshort)
|
||||
_element.Value = asUshort;
|
||||
else if (value is byte asByte)
|
||||
_element.Value = asByte;
|
||||
else if (value is sbyte asSbyte)
|
||||
_element.Value = asSbyte;
|
||||
else
|
||||
throw new Exception(string.Format("Invalid value type {0}.", value?.GetType().ToString() ?? "<null>"));
|
||||
}
|
||||
@@ -338,7 +354,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
protected abstract ulong GetValue(object value);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the value from long.
|
||||
/// Sets the value from long.
|
||||
/// </summary>
|
||||
/// <param name="value">The value from editor.</param>
|
||||
/// <returns>The value to object.</returns>
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace FlaxEditor.CustomEditors.Editors
|
||||
if (watermarkAttribute is WatermarkAttribute watermark)
|
||||
{
|
||||
_watermarkText = watermark.WatermarkText;
|
||||
var watermarkColor = watermark.WatermarkColor > 0 ? Color.FromRGBA(watermark.WatermarkColor) : FlaxEngine.GUI.Style.Current.ForegroundDisabled;
|
||||
var watermarkColor = watermark.WatermarkColor > 0 ? Color.FromRGB(watermark.WatermarkColor) : FlaxEngine.GUI.Style.Current.ForegroundDisabled;
|
||||
_watermarkColor = watermarkColor;
|
||||
_element.TextBox.WatermarkText = watermark.WatermarkText;
|
||||
_element.TextBox.WatermarkTextColor = watermarkColor;
|
||||
|
||||
@@ -242,7 +242,7 @@ namespace FlaxEditor.CustomEditors.GUI
|
||||
float namesWidth = _splitterValue * Width;
|
||||
int count = _element.Labels.Count;
|
||||
float[] yStarts = new float[count + 1];
|
||||
for (int i = 1; i < count; i++)
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var label = _element.Labels[i];
|
||||
|
||||
@@ -251,9 +251,13 @@ namespace FlaxEditor.CustomEditors.GUI
|
||||
else if (_children.Count <= label.FirstChildControlIndex)
|
||||
yStarts[i] = y;
|
||||
else
|
||||
{
|
||||
yStarts[i] = _children[label.FirstChildControlIndex].Top;
|
||||
if (i == count - 1)
|
||||
yStarts[i + 1] = _children[label.FirstChildControlIndex].Bottom;
|
||||
}
|
||||
|
||||
}
|
||||
yStarts[count] = y;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
var label = _element.Labels[i];
|
||||
|
||||
@@ -318,7 +318,9 @@ namespace FlaxEditor.CustomEditors
|
||||
if (header.FontSize > 0)
|
||||
element.Label.Font = new FontReference(element.Label.Font.Font, header.FontSize);
|
||||
if (header.Color > 0)
|
||||
element.Label.TextColor = Color.FromRGBA(header.Color);
|
||||
element.Label.TextColor = Color.FromRGB(header.Color);
|
||||
var size = element.Label.Font.GetFont().MeasureText(header.Text);
|
||||
element.Label.Height = size.Y;
|
||||
return element;
|
||||
}
|
||||
|
||||
|
||||
@@ -247,6 +247,11 @@ namespace FlaxEditor
|
||||
/// </summary>
|
||||
public event Action PlayModeEnd;
|
||||
|
||||
/// <summary>
|
||||
/// Fired on Editor update
|
||||
/// </summary>
|
||||
public event Action EditorUpdate;
|
||||
|
||||
internal Editor()
|
||||
{
|
||||
Instance = this;
|
||||
@@ -330,7 +335,7 @@ namespace FlaxEditor
|
||||
}
|
||||
case GeneralOptions.StartupSceneModes.LastOpened:
|
||||
{
|
||||
if (ProjectCache.TryGetCustomData(ProjectDataLastScene, out var lastSceneIdName))
|
||||
if (ProjectCache.TryGetCustomData(ProjectDataLastScene, out string lastSceneIdName))
|
||||
{
|
||||
var lastScenes = JsonSerializer.Deserialize<Guid[]>(lastSceneIdName);
|
||||
foreach (var scene in lastScenes)
|
||||
@@ -442,7 +447,7 @@ namespace FlaxEditor
|
||||
}
|
||||
case GeneralOptions.StartupSceneModes.LastOpened:
|
||||
{
|
||||
if (ProjectCache.TryGetCustomData(ProjectDataLastScene, out var lastSceneIdName))
|
||||
if (ProjectCache.TryGetCustomData(ProjectDataLastScene, out string lastSceneIdName))
|
||||
{
|
||||
var lastScenes = JsonSerializer.Deserialize<Guid[]>(lastSceneIdName);
|
||||
foreach (var sceneId in lastScenes)
|
||||
@@ -459,7 +464,7 @@ namespace FlaxEditor
|
||||
}
|
||||
|
||||
// Restore view
|
||||
if (ProjectCache.TryGetCustomData(ProjectDataLastSceneSpawn, out var lastSceneSpawnName))
|
||||
if (ProjectCache.TryGetCustomData(ProjectDataLastSceneSpawn, out string lastSceneSpawnName))
|
||||
Windows.EditWin.Viewport.ViewRay = JsonSerializer.Deserialize<Ray>(lastSceneSpawnName);
|
||||
}
|
||||
break;
|
||||
@@ -485,6 +490,8 @@ namespace FlaxEditor
|
||||
{
|
||||
StateMachine.CurrentState.UpdateFPS();
|
||||
}
|
||||
|
||||
EditorUpdate?.Invoke();
|
||||
|
||||
// Update modules
|
||||
for (int i = 0; i < _modules.Count; i++)
|
||||
@@ -1364,6 +1371,7 @@ namespace FlaxEditor
|
||||
public byte AutoReloadScriptsOnMainWindowFocus;
|
||||
public byte ForceScriptCompilationOnStartup;
|
||||
public byte UseAssetImportPathRelative;
|
||||
public byte EnableParticlesPreview;
|
||||
public byte AutoRebuildCSG;
|
||||
public float AutoRebuildCSGTimeoutMs;
|
||||
public byte AutoRebuildNavMesh;
|
||||
|
||||
@@ -105,9 +105,9 @@ namespace FlaxEditor.GUI
|
||||
|
||||
private Rectangle Button1Rect => new Rectangle(Height + ButtonsOffset, 0, ButtonsSize, ButtonsSize);
|
||||
|
||||
private Rectangle Button2Rect => new Rectangle(Height + ButtonsOffset, ButtonsSize, ButtonsSize, ButtonsSize);
|
||||
private Rectangle Button2Rect => new Rectangle(Height + ButtonsOffset, ButtonsSize + 2, ButtonsSize, ButtonsSize);
|
||||
|
||||
private Rectangle Button3Rect => new Rectangle(Height + ButtonsOffset, ButtonsSize * 2, ButtonsSize, ButtonsSize);
|
||||
private Rectangle Button3Rect => new Rectangle(Height + ButtonsOffset, (ButtonsSize + 2) * 2, ButtonsSize, ButtonsSize);
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
@@ -149,6 +149,13 @@ namespace FlaxEditor.GUI
|
||||
style.Foreground,
|
||||
TextAlignment.Near,
|
||||
TextAlignment.Center);
|
||||
Render2D.DrawText(
|
||||
style.FontSmall,
|
||||
$"{TypeUtils.GetTypeDisplayName(Validator.AssetType.Type)}",
|
||||
new Rectangle(button1Rect.Right + 2, ButtonsSize + 2, sizeForTextLeft, ButtonsSize),
|
||||
style.ForegroundGrey,
|
||||
TextAlignment.Near,
|
||||
TextAlignment.Center);
|
||||
}
|
||||
}
|
||||
// Check if has no item but has an asset (eg. virtual asset)
|
||||
@@ -171,6 +178,13 @@ namespace FlaxEditor.GUI
|
||||
style.Foreground,
|
||||
TextAlignment.Near,
|
||||
TextAlignment.Center);
|
||||
Render2D.DrawText(
|
||||
style.FontSmall,
|
||||
$"{TypeUtils.GetTypeDisplayName(Validator.AssetType.Type)}",
|
||||
new Rectangle(button1Rect.Right + 2, ButtonsSize + 2, sizeForTextLeft, ButtonsSize),
|
||||
style.ForegroundGrey,
|
||||
TextAlignment.Near,
|
||||
TextAlignment.Center);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -178,6 +192,24 @@ namespace FlaxEditor.GUI
|
||||
// No element selected
|
||||
Render2D.FillRectangle(iconRect, style.BackgroundNormal);
|
||||
Render2D.DrawText(style.FontMedium, "No asset\nselected", iconRect, Color.Orange, TextAlignment.Center, TextAlignment.Center, TextWrapping.NoWrap, 1.0f, Height / DefaultIconSize);
|
||||
float sizeForTextLeft = Width - button1Rect.Right;
|
||||
if (sizeForTextLeft > 30)
|
||||
{
|
||||
Render2D.DrawText(
|
||||
style.FontSmall,
|
||||
$"None",
|
||||
new Rectangle(button1Rect.Right + 2, 0, sizeForTextLeft, ButtonsSize),
|
||||
style.Foreground,
|
||||
TextAlignment.Near,
|
||||
TextAlignment.Center);
|
||||
Render2D.DrawText(
|
||||
style.FontSmall,
|
||||
$"{TypeUtils.GetTypeDisplayName(Validator.AssetType.Type)}",
|
||||
new Rectangle(button1Rect.Right + 2, ButtonsSize + 2, sizeForTextLeft, ButtonsSize),
|
||||
style.ForegroundGrey,
|
||||
TextAlignment.Near,
|
||||
TextAlignment.Center);
|
||||
}
|
||||
}
|
||||
|
||||
// Check if drag is over
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
|
||||
namespace FlaxEditor.GUI
|
||||
{
|
||||
@@ -43,10 +44,20 @@ namespace FlaxEditor.GUI
|
||||
public Color TitleColor = Color.White;
|
||||
|
||||
/// <summary>
|
||||
/// The column title background background.
|
||||
/// The column title background color.
|
||||
/// </summary>
|
||||
public Color TitleBackgroundColor = Color.Brown;
|
||||
|
||||
/// <summary>
|
||||
/// The column title horizontal text alignment
|
||||
/// </summary>
|
||||
public TextAlignment TitleAlignment = TextAlignment.Near;
|
||||
|
||||
/// <summary>
|
||||
/// The column title margin.
|
||||
/// </summary>
|
||||
public Margin TitleMargin = new Margin(4, 4, 0, 0);
|
||||
|
||||
/// <summary>
|
||||
/// The minimum size (in pixels) of the column.
|
||||
/// </summary>
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
||||
#define USE_IS_FOREGROUND
|
||||
#else
|
||||
#endif
|
||||
#if PLATFORM_SDL
|
||||
#define USE_SDL_WORKAROUNDS
|
||||
#endif
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
using System.Collections.Generic;
|
||||
@@ -111,7 +114,7 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Shows the empty menu popup o na screen.
|
||||
/// Shows the empty menu popup on a screen.
|
||||
/// </summary>
|
||||
/// <param name="control">The target control.</param>
|
||||
/// <param name="area">The target control area to cover.</param>
|
||||
@@ -215,7 +218,7 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
desc.AllowMaximize = false;
|
||||
desc.AllowDragAndDrop = false;
|
||||
desc.IsTopmost = true;
|
||||
desc.IsRegularWindow = false;
|
||||
desc.Type = WindowType.Utility;
|
||||
desc.HasSizingFrame = false;
|
||||
OnWindowCreating(ref desc);
|
||||
_window = Platform.CreateWindow(ref desc);
|
||||
@@ -228,8 +231,6 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
|
||||
// Show
|
||||
Visible = true;
|
||||
if (_window == null)
|
||||
return;
|
||||
_window.Show();
|
||||
PerformLayout();
|
||||
_previouslyFocused = parentWin.FocusedControl;
|
||||
@@ -378,6 +379,11 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
}
|
||||
}
|
||||
|
||||
#if USE_SDL_WORKAROUNDS
|
||||
private void OnWindowGotFocus()
|
||||
{
|
||||
}
|
||||
#else
|
||||
private void OnWindowGotFocus()
|
||||
{
|
||||
var child = _childCM;
|
||||
@@ -391,6 +397,7 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
});
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
private void OnWindowLostFocus()
|
||||
{
|
||||
@@ -489,7 +496,12 @@ namespace FlaxEditor.GUI.ContextMenu
|
||||
// Let root context menu to check if none of the popup windows
|
||||
if (_parentCM == null && !IsForeground)
|
||||
{
|
||||
#if USE_SDL_WORKAROUNDS
|
||||
if (!IsMouseOver)
|
||||
Hide();
|
||||
#else
|
||||
Hide();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -40,6 +40,7 @@ namespace FlaxEditor.GUI.Dialogs
|
||||
private bool _disableEvents;
|
||||
private bool _useDynamicEditing;
|
||||
private bool _activeEyedropper;
|
||||
private bool _canPassLastChangeEvent = true;
|
||||
private ColorValueBox.ColorPickerEvent _onChanged;
|
||||
private ColorValueBox.ColorPickerClosedEvent _onClosed;
|
||||
|
||||
@@ -119,10 +120,8 @@ namespace FlaxEditor.GUI.Dialogs
|
||||
_onClosed = pickerClosed;
|
||||
|
||||
// Get saved colors if they exist
|
||||
if (Editor.Instance.ProjectCache.TryGetCustomData("ColorPickerSavedColors", out var savedColors))
|
||||
{
|
||||
if (Editor.Instance.ProjectCache.TryGetCustomData("ColorPickerSavedColors", out string savedColors))
|
||||
_savedColors = JsonSerializer.Deserialize<List<Color>>(savedColors);
|
||||
}
|
||||
|
||||
// Selector
|
||||
_cSelector = new ColorSelectorWithSliders(180, 18)
|
||||
@@ -264,6 +263,7 @@ namespace FlaxEditor.GUI.Dialogs
|
||||
{
|
||||
Text = "+",
|
||||
Parent = this,
|
||||
TooltipText = "Save Color.",
|
||||
Tag = null,
|
||||
};
|
||||
savedColorButton.ButtonClicked += (b) => OnSavedColorButtonClicked(b);
|
||||
@@ -370,9 +370,25 @@ namespace FlaxEditor.GUI.Dialogs
|
||||
Render2D.DrawText(style.FontMedium, "Hex", hex, textColor, TextAlignment.Near, TextAlignment.Center);
|
||||
|
||||
// Color difference
|
||||
var newRect = new Rectangle(_cOK.X, _cHex.Bottom + PickerMargin, _cCancel.Right - _cOK.Left, 0);
|
||||
newRect.Size.Y = _cValue.Bottom - newRect.Y;
|
||||
Render2D.FillRectangle(newRect, _value * _value.A);
|
||||
var newRect = new Rectangle(_cOK.X - 3, _cHex.Bottom + PickerMargin, 130, 0);
|
||||
newRect.Size.Y = 50;
|
||||
Render2D.FillRectangle(newRect, Color.White);
|
||||
var smallRectSize = 10;
|
||||
var numHor = Mathf.FloorToInt(newRect.Width / smallRectSize);
|
||||
var numVer = Mathf.FloorToInt(newRect.Height / smallRectSize);
|
||||
// Draw checkerboard for background of color to help with transparency
|
||||
for (int i = 0; i < numHor; i++)
|
||||
{
|
||||
for (int j = 0; j < numVer; j++)
|
||||
{
|
||||
if ((i + j) % 2 == 0)
|
||||
{
|
||||
var rect = new Rectangle(newRect.X + smallRectSize * i, newRect.Y + smallRectSize * j, new Float2(smallRectSize));
|
||||
Render2D.FillRectangle(rect, Color.Gray);
|
||||
}
|
||||
}
|
||||
}
|
||||
Render2D.FillRectangle(newRect, _value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -380,7 +396,7 @@ namespace FlaxEditor.GUI.Dialogs
|
||||
{
|
||||
// Auto cancel on lost focus
|
||||
#if !PLATFORM_LINUX
|
||||
((WindowRootControl)Root).Window.LostFocus += OnCancel;
|
||||
((WindowRootControl)Root).Window.LostFocus += OnWindowLostFocus;
|
||||
#endif
|
||||
|
||||
base.OnShow();
|
||||
@@ -489,7 +505,7 @@ namespace FlaxEditor.GUI.Dialogs
|
||||
BackgroundColorHighlighted = savedColor,
|
||||
BackgroundColorSelected = savedColor.RGBMultiplied(0.8f),
|
||||
};
|
||||
savedColorButton.ButtonClicked += (b) => OnSavedColorButtonClicked(b);
|
||||
savedColorButton.ButtonClicked += OnSavedColorButtonClicked;
|
||||
_savedColorButtons.Add(savedColorButton);
|
||||
}
|
||||
if (_savedColors.Count < 8)
|
||||
@@ -498,13 +514,27 @@ namespace FlaxEditor.GUI.Dialogs
|
||||
{
|
||||
Text = "+",
|
||||
Parent = this,
|
||||
TooltipText = "Save Color.",
|
||||
Tag = null,
|
||||
};
|
||||
savedColorButton.ButtonClicked += (b) => OnSavedColorButtonClicked(b);
|
||||
savedColorButton.ButtonClicked += OnSavedColorButtonClicked;
|
||||
_savedColorButtons.Add(savedColorButton);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnWindowLostFocus()
|
||||
{
|
||||
// Auto apply color on defocus
|
||||
var autoAcceptColorPickerChange = Editor.Instance.Options.Options.Interface.AutoAcceptColorPickerChange;
|
||||
if (_useDynamicEditing && _initialValue != _value && _canPassLastChangeEvent && autoAcceptColorPickerChange)
|
||||
{
|
||||
_canPassLastChangeEvent = false;
|
||||
_onChanged?.Invoke(_value, false);
|
||||
}
|
||||
|
||||
OnCancel();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnSubmit()
|
||||
{
|
||||
@@ -529,8 +559,9 @@ namespace FlaxEditor.GUI.Dialogs
|
||||
_disableEvents = true;
|
||||
|
||||
// Restore color if modified
|
||||
if (_useDynamicEditing && _initialValue != _value)
|
||||
if (_useDynamicEditing && _initialValue != _value && _canPassLastChangeEvent)
|
||||
{
|
||||
_canPassLastChangeEvent = false;
|
||||
_onChanged?.Invoke(_initialValue, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -311,7 +311,9 @@ namespace FlaxEditor.GUI.Dialogs
|
||||
// Alpha
|
||||
float alphaY = _slider2Rect.Height * (1 - _color.A);
|
||||
var alphaR = new Rectangle(_slider2Rect.X - slidersOffset, _slider2Rect.Y + alphaY - slidersThickness / 2, _slider2Rect.Width + slidersOffset * 2, slidersThickness);
|
||||
Render2D.FillRectangle(_slider2Rect, _color, _color, Color.Transparent, Color.Transparent);
|
||||
var color = _color;
|
||||
color.A = 1; // Keep slider 2 fill rect from changing color alpha while selecting.
|
||||
Render2D.FillRectangle(_slider2Rect, color, color, Color.Transparent, Color.Transparent);
|
||||
Render2D.DrawRectangle(_slider2Rect, _isMouseDownSlider2 ? style.BackgroundSelected : Color.Black);
|
||||
Render2D.DrawRectangle(alphaR, _isMouseDownSlider2 ? Color.White : Color.Gray);
|
||||
}
|
||||
|
||||
@@ -67,9 +67,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
Proxy.Window.MouseUp += OnMouseUp;
|
||||
Proxy.Window.MouseMove += OnMouseMove;
|
||||
Proxy.Window.LostFocus += OnLostFocus;
|
||||
|
||||
// Start tracking mouse
|
||||
Proxy.Window.StartTrackingMouse(false);
|
||||
_toMove.Window.Window.MouseUp += OnMouseUp; // Intercept the drag release mouse event from source window
|
||||
|
||||
// Update window GUI
|
||||
Proxy.Window.GUI.PerformLayout();
|
||||
@@ -77,13 +75,16 @@ namespace FlaxEditor.GUI.Docking
|
||||
// Update rectangles
|
||||
UpdateRects();
|
||||
|
||||
// Hide base window
|
||||
window.Hide();
|
||||
|
||||
// Enable hit window presentation
|
||||
Proxy.Window.RenderingEnabled = true;
|
||||
Proxy.Window.Show();
|
||||
Proxy.Window.Focus();
|
||||
|
||||
// Hide base window
|
||||
window.Hide();
|
||||
|
||||
// Start tracking mouse
|
||||
Proxy.Window.StartTrackingMouse(false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -101,6 +102,8 @@ namespace FlaxEditor.GUI.Docking
|
||||
Proxy.Window.MouseUp -= OnMouseUp;
|
||||
Proxy.Window.MouseMove -= OnMouseMove;
|
||||
Proxy.Window.LostFocus -= OnLostFocus;
|
||||
if (_toMove?.Window?.Window)
|
||||
_toMove.Window.Window.MouseUp -= OnMouseUp;
|
||||
|
||||
// Hide the proxy
|
||||
Proxy.Hide();
|
||||
@@ -438,7 +441,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
settings.AllowMinimize = false;
|
||||
settings.HasBorder = false;
|
||||
settings.HasSizingFrame = false;
|
||||
settings.IsRegularWindow = false;
|
||||
settings.Type = WindowType.Utility;
|
||||
settings.SupportsTransparency = true;
|
||||
settings.ShowInTaskbar = false;
|
||||
settings.ShowAfterFirstPaint = false;
|
||||
@@ -470,7 +473,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
settings.AllowMinimize = false;
|
||||
settings.HasBorder = false;
|
||||
settings.HasSizingFrame = false;
|
||||
settings.IsRegularWindow = false;
|
||||
settings.Type = WindowType.Utility;
|
||||
settings.SupportsTransparency = true;
|
||||
settings.ShowInTaskbar = false;
|
||||
settings.ActivateWhenFirstShown = false;
|
||||
|
||||
@@ -629,7 +629,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
|
||||
internal void MoveTabRight(int index)
|
||||
{
|
||||
if (index < _tabs.Count - 2)
|
||||
if (index < _tabs.Count - 1)
|
||||
{
|
||||
var tab = _tabs[index];
|
||||
_tabs.RemoveAt(index);
|
||||
|
||||
@@ -51,6 +51,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
public DockWindow StartDragAsyncWindow;
|
||||
|
||||
private Rectangle HeaderRectangle => new Rectangle(0, 0, Width, DockPanel.DefaultHeaderHeight);
|
||||
private bool IsSingleFloatingWindow => _panel.TabsCount == 1 && _panel.IsFloating && _panel.ChildPanelsCount == 0;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="DockPanelProxy"/> class.
|
||||
@@ -187,6 +188,10 @@ namespace FlaxEditor.GUI.Docking
|
||||
var headerRect = HeaderRectangle;
|
||||
var tabsCount = _panel.TabsCount;
|
||||
|
||||
// Return and don't draw tab if only 1 window and it is floating
|
||||
if (IsSingleFloatingWindow)
|
||||
return;
|
||||
|
||||
// Check if has only one window docked
|
||||
if (tabsCount == 1)
|
||||
{
|
||||
@@ -321,6 +326,9 @@ namespace FlaxEditor.GUI.Docking
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDoubleClick(Float2 location, MouseButton button)
|
||||
{
|
||||
if (IsSingleFloatingWindow)
|
||||
return base.OnMouseDoubleClick(location, button);
|
||||
|
||||
// Maximize/restore on double click
|
||||
var tab = GetTabAtPos(location, out _);
|
||||
var rootWindow = tab?.RootWindow;
|
||||
@@ -339,6 +347,8 @@ namespace FlaxEditor.GUI.Docking
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||
{
|
||||
if (IsSingleFloatingWindow)
|
||||
return base.OnMouseDown(location, button);
|
||||
MouseDownWindow = GetTabAtPos(location, out IsMouseDownOverCross);
|
||||
|
||||
// Check buttons
|
||||
@@ -368,6 +378,9 @@ namespace FlaxEditor.GUI.Docking
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
if (IsSingleFloatingWindow)
|
||||
return base.OnMouseUp(location, button);
|
||||
|
||||
// Check tabs under mouse position at the beginning and at the end
|
||||
var tab = GetTabAtPos(location, out var overCross);
|
||||
|
||||
@@ -410,7 +423,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
public override void OnMouseMove(Float2 location)
|
||||
{
|
||||
MousePosition = location;
|
||||
if (IsMouseLeftButtonDown)
|
||||
if (IsMouseLeftButtonDown && !IsSingleFloatingWindow)
|
||||
{
|
||||
// Check if mouse is outside the header
|
||||
if (!HeaderRectangle.Contains(location))
|
||||
@@ -501,7 +514,10 @@ namespace FlaxEditor.GUI.Docking
|
||||
/// <inheritdoc />
|
||||
public override void GetDesireClientArea(out Rectangle rect)
|
||||
{
|
||||
rect = new Rectangle(0, DockPanel.DefaultHeaderHeight, Width, Height - DockPanel.DefaultHeaderHeight);
|
||||
if (IsSingleFloatingWindow)
|
||||
rect = new Rectangle(0, 0, Width, Height);
|
||||
else
|
||||
rect = new Rectangle(0, DockPanel.DefaultHeaderHeight, Width, Height - DockPanel.DefaultHeaderHeight);
|
||||
}
|
||||
|
||||
private DragDropEffect TrySelectTabUnderLocation(ref Float2 location)
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace FlaxEditor.GUI.Docking
|
||||
settings.AllowMaximize = true;
|
||||
settings.AllowDragAndDrop = true;
|
||||
settings.IsTopmost = false;
|
||||
settings.IsRegularWindow = true;
|
||||
settings.Type = WindowType.Regular;
|
||||
settings.HasSizingFrame = true;
|
||||
settings.ShowAfterFirstPaint = false;
|
||||
settings.ShowInTaskbar = true;
|
||||
|
||||
@@ -130,7 +130,7 @@ namespace FlaxEditor.GUI.Input
|
||||
base.Draw();
|
||||
|
||||
var style = Style.Current;
|
||||
var r = new Rectangle(2, 2, Width - 4, Height - 4);
|
||||
var r = new Rectangle(0, 0, Width, Height);
|
||||
|
||||
Render2D.FillRectangle(r, _value);
|
||||
Render2D.DrawRectangle(r, IsMouseOver || IsNavFocused ? style.BackgroundSelected : Color.Black);
|
||||
|
||||
@@ -132,6 +132,8 @@ namespace FlaxEditor.GUI.Input
|
||||
_isSliding = false;
|
||||
EndMouseCapture();
|
||||
SlidingEnd?.Invoke();
|
||||
Defocus();
|
||||
Parent?.Focus();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -183,6 +185,8 @@ namespace FlaxEditor.GUI.Input
|
||||
{
|
||||
// Click change
|
||||
Value += (mousePosition < _thumbCenter ? -1 : 1) * 10;
|
||||
Defocus();
|
||||
Parent?.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,6 +201,10 @@ namespace FlaxEditor.GUI.Input
|
||||
// Update sliding
|
||||
var slidePosition = location + Root.TrackingMouseOffset;
|
||||
Value = Mathf.Remap(slidePosition.X, 4, TrackSize - 4, Minimum, Maximum);
|
||||
if (Mathf.NearEqual(Value, Maximum))
|
||||
Value = Maximum;
|
||||
else if (Mathf.NearEqual(Value, Minimum))
|
||||
Value = Minimum;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -364,7 +372,7 @@ namespace FlaxEditor.GUI.Input
|
||||
};
|
||||
_slider.ValueChanged += SliderOnValueChanged;
|
||||
_slider.SlidingStart += SlidingStart;
|
||||
_slider.SlidingEnd += SlidingEnd;
|
||||
_slider.SlidingEnd += SliderOnSliderEnd;
|
||||
_textBox = new TextBox(false, split, 0)
|
||||
{
|
||||
Text = _value.ToString(CultureInfo.InvariantCulture),
|
||||
@@ -375,6 +383,13 @@ namespace FlaxEditor.GUI.Input
|
||||
_textBox.EditEnd += OnTextBoxEditEnd;
|
||||
}
|
||||
|
||||
private void SliderOnSliderEnd()
|
||||
{
|
||||
SlidingEnd?.Invoke();
|
||||
Defocus();
|
||||
Parent?.Focus();
|
||||
}
|
||||
|
||||
private void SliderOnValueChanged()
|
||||
{
|
||||
if (_valueIsChanging)
|
||||
@@ -397,6 +412,8 @@ namespace FlaxEditor.GUI.Input
|
||||
{
|
||||
UpdateText();
|
||||
}
|
||||
Defocus();
|
||||
Parent?.Focus();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -266,6 +266,7 @@ namespace FlaxEditor.GUI.Input
|
||||
return base.OnMouseDown(location, button);
|
||||
}
|
||||
|
||||
#if !PLATFORM_SDL
|
||||
/// <inheritdoc />
|
||||
public override void OnMouseMove(Float2 location)
|
||||
{
|
||||
@@ -292,6 +293,36 @@ namespace FlaxEditor.GUI.Input
|
||||
base.OnMouseMove(location);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnMouseMoveRelative(Float2 mouseMotion)
|
||||
{
|
||||
var location = Root.TrackingMouseOffset;
|
||||
if (_isSliding)
|
||||
{
|
||||
// Update sliding
|
||||
ApplySliding(Root.TrackingMouseOffset.X * _slideSpeed);
|
||||
return;
|
||||
}
|
||||
|
||||
// Update cursor type so user knows they can slide value
|
||||
if (CanUseSliding && SlideRect.Contains(location) && !_isSliding)
|
||||
{
|
||||
Cursor = CursorType.SizeWE;
|
||||
_cursorChanged = true;
|
||||
}
|
||||
else if (_cursorChanged && !_isSliding)
|
||||
{
|
||||
Cursor = CursorType.Default;
|
||||
_cursorChanged = false;
|
||||
}
|
||||
|
||||
base.OnMouseMoveRelative(mouseMotion);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
|
||||
@@ -23,6 +23,9 @@ namespace FlaxEditor.GUI
|
||||
[HideInEditor]
|
||||
public class Item : Control
|
||||
{
|
||||
private bool _isStartsWithMatch;
|
||||
private bool _isFullMatch;
|
||||
|
||||
/// <summary>
|
||||
/// The is mouse down flag.
|
||||
/// </summary>
|
||||
@@ -43,6 +46,11 @@ namespace FlaxEditor.GUI
|
||||
/// </summary>
|
||||
public string Category;
|
||||
|
||||
/// <summary>
|
||||
/// A computed score for the context menu order
|
||||
/// </summary>
|
||||
public float SortScore;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when items gets clicked by the user.
|
||||
/// </summary>
|
||||
@@ -61,44 +69,69 @@ namespace FlaxEditor.GUI
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the <see cref="SortScore"/>
|
||||
/// </summary>
|
||||
public void UpdateScore()
|
||||
{
|
||||
SortScore = 0;
|
||||
|
||||
if (!Visible)
|
||||
return;
|
||||
|
||||
if (_highlights is { Count: > 0 })
|
||||
SortScore += 1;
|
||||
if (_isStartsWithMatch)
|
||||
SortScore += 2;
|
||||
if (_isFullMatch)
|
||||
SortScore += 5;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the filter.
|
||||
/// </summary>
|
||||
/// <param name="filterText">The filter text.</param>
|
||||
public void UpdateFilter(string filterText)
|
||||
{
|
||||
_isStartsWithMatch = _isFullMatch = false;
|
||||
|
||||
if (string.IsNullOrWhiteSpace(filterText))
|
||||
{
|
||||
// Clear filter
|
||||
_highlights?.Clear();
|
||||
Visible = true;
|
||||
return;
|
||||
}
|
||||
else
|
||||
|
||||
if (QueryFilterHelper.Match(filterText, Name, out var ranges))
|
||||
{
|
||||
if (QueryFilterHelper.Match(filterText, Name, out var ranges))
|
||||
{
|
||||
// Update highlights
|
||||
if (_highlights == null)
|
||||
_highlights = new List<Rectangle>(ranges.Length);
|
||||
else
|
||||
_highlights.Clear();
|
||||
var style = Style.Current;
|
||||
var font = style.FontSmall;
|
||||
for (int i = 0; i < ranges.Length; i++)
|
||||
{
|
||||
var start = font.GetCharPosition(Name, ranges[i].StartIndex);
|
||||
var end = font.GetCharPosition(Name, ranges[i].EndIndex);
|
||||
_highlights.Add(new Rectangle(start.X + 2, 0, end.X - start.X, Height));
|
||||
}
|
||||
Visible = true;
|
||||
}
|
||||
// Update highlights
|
||||
if (_highlights == null)
|
||||
_highlights = new List<Rectangle>(ranges.Length);
|
||||
else
|
||||
_highlights.Clear();
|
||||
var style = Style.Current;
|
||||
var font = style.FontSmall;
|
||||
for (int i = 0; i < ranges.Length; i++)
|
||||
{
|
||||
// Hide
|
||||
_highlights?.Clear();
|
||||
Visible = false;
|
||||
var start = font.GetCharPosition(Name, ranges[i].StartIndex);
|
||||
var end = font.GetCharPosition(Name, ranges[i].EndIndex);
|
||||
_highlights.Add(new Rectangle(start.X + 2, 0, end.X - start.X, Height));
|
||||
|
||||
if (ranges[i].StartIndex <= 0)
|
||||
{
|
||||
_isStartsWithMatch = true;
|
||||
if (ranges[i].Length == Name.Length)
|
||||
_isFullMatch = true;
|
||||
}
|
||||
}
|
||||
Visible = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Hide
|
||||
_highlights?.Clear();
|
||||
Visible = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -178,7 +211,14 @@ namespace FlaxEditor.GUI
|
||||
public override int Compare(Control other)
|
||||
{
|
||||
if (other is Item otherItem)
|
||||
return string.Compare(Name, otherItem.Name, StringComparison.Ordinal);
|
||||
{
|
||||
int order = -1 * SortScore.CompareTo(otherItem.SortScore);
|
||||
if (order == 0)
|
||||
{
|
||||
order = string.Compare(Name, otherItem.Name, StringComparison.Ordinal);
|
||||
}
|
||||
return order;
|
||||
}
|
||||
return base.Compare(other);
|
||||
}
|
||||
}
|
||||
@@ -249,7 +289,10 @@ namespace FlaxEditor.GUI
|
||||
for (int i = 0; i < items.Count; i++)
|
||||
{
|
||||
if (items[i] is Item item)
|
||||
{
|
||||
item.UpdateFilter(_searchBox.Text);
|
||||
item.UpdateScore();
|
||||
}
|
||||
}
|
||||
if (_categoryPanels != null)
|
||||
{
|
||||
@@ -262,6 +305,7 @@ namespace FlaxEditor.GUI
|
||||
if (category.Children[j] is Item item2)
|
||||
{
|
||||
item2.UpdateFilter(_searchBox.Text);
|
||||
item2.UpdateScore();
|
||||
anyVisible |= item2.Visible;
|
||||
}
|
||||
}
|
||||
@@ -273,6 +317,8 @@ namespace FlaxEditor.GUI
|
||||
}
|
||||
}
|
||||
|
||||
SortItems();
|
||||
|
||||
UnlockChildrenRecursive();
|
||||
PerformLayout(true);
|
||||
_searchBox.Focus();
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace FlaxEditor.GUI
|
||||
/// <seealso cref="FlaxEngine.GUI.ContainerControl" />
|
||||
public sealed class MainMenu : ContainerControl
|
||||
{
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
||||
private bool _useCustomWindowSystem;
|
||||
private Image _icon;
|
||||
private Label _title;
|
||||
@@ -67,7 +67,7 @@ namespace FlaxEditor.GUI
|
||||
AutoFocus = false;
|
||||
AnchorPreset = AnchorPresets.HorizontalStretchTop;
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
||||
_useCustomWindowSystem = !Editor.Instance.Options.Options.Interface.UseNativeWindowSystem;
|
||||
if (_useCustomWindowSystem)
|
||||
{
|
||||
@@ -166,7 +166,7 @@ namespace FlaxEditor.GUI
|
||||
}
|
||||
}
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
||||
/// <inheritdoc />
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
@@ -291,7 +291,7 @@ namespace FlaxEditor.GUI
|
||||
if (base.OnMouseDoubleClick(location, button))
|
||||
return true;
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
||||
var child = GetChildAtRecursive(location);
|
||||
if (_useCustomWindowSystem && child is not Button && child is not MainMenuButton)
|
||||
{
|
||||
@@ -321,7 +321,7 @@ namespace FlaxEditor.GUI
|
||||
{
|
||||
float x = 0;
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
||||
if (_useCustomWindowSystem)
|
||||
{
|
||||
// Icon
|
||||
@@ -349,7 +349,7 @@ namespace FlaxEditor.GUI
|
||||
}
|
||||
}
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
||||
if (_useCustomWindowSystem)
|
||||
{
|
||||
// Buttons
|
||||
@@ -367,7 +367,7 @@ namespace FlaxEditor.GUI
|
||||
#endif
|
||||
}
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace FlaxEditor.GUI
|
||||
Text = text;
|
||||
|
||||
var style = Style.Current;
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
||||
if (Editor.Instance.Options.Options.Interface.UseNativeWindowSystem)
|
||||
{
|
||||
BackgroundColorMouseOver = style.BackgroundHighlighted;
|
||||
|
||||
@@ -38,7 +38,7 @@ namespace FlaxEditor.GUI
|
||||
ContentItem = item;
|
||||
ContentItem.AddReference(this);
|
||||
|
||||
Name = item.ShortName;
|
||||
OnItemRenamed(item);
|
||||
TooltipText = item.Path;
|
||||
|
||||
Height = IconSize + 4;
|
||||
@@ -82,7 +82,9 @@ namespace FlaxEditor.GUI
|
||||
/// <inheritdoc />
|
||||
public void OnItemRenamed(ContentItem item)
|
||||
{
|
||||
Name = ContentItem.ShortName;
|
||||
Name = item.ShortName;
|
||||
if (item is ScriptItem)
|
||||
Name = item.FileName; // Show extension for scripts (esp. for .h and .cpp files of the same name)
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -130,12 +130,14 @@ namespace FlaxEditor.GUI
|
||||
|
||||
var style = Style.Current;
|
||||
var font = column.TitleFont ?? style.FontMedium;
|
||||
Render2D.DrawText(font, column.Title, rect, column.TitleColor, TextAlignment.Center, TextAlignment.Center);
|
||||
var textRect = rect;
|
||||
column.TitleMargin.ShrinkRectangle(ref textRect);
|
||||
Render2D.DrawText(font, column.Title, textRect, column.TitleColor, column.TitleAlignment, TextAlignment.Center);
|
||||
|
||||
if (columnIndex < _columns.Length - 1)
|
||||
{
|
||||
var splitRect = new Rectangle(rect.Right - 1, 2, 2, rect.Height - 4);
|
||||
Render2D.FillRectangle(splitRect, _movingSplit == columnIndex || splitRect.Contains(_mousePos) ? style.BorderNormal : column.TitleBackgroundColor * 0.9f);
|
||||
var splitRect = new Rectangle(rect.Right - 2, 2, 4, rect.Height - 4);
|
||||
Render2D.FillRectangle(splitRect, _movingSplit == columnIndex || splitRect.Contains(_mousePos) ? style.BorderNormal : style.Background * 0.9f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,7 +153,7 @@ namespace FlaxEditor.GUI
|
||||
{
|
||||
rect.Width = GetColumnWidth(i);
|
||||
|
||||
var splitRect = new Rectangle(rect.Right - 1, 2, 2, rect.Height - 4);
|
||||
var splitRect = new Rectangle(rect.Right - 2, 2, 4, rect.Height - 4);
|
||||
if (splitRect.Contains(location))
|
||||
{
|
||||
// Start moving splitter
|
||||
@@ -193,6 +195,31 @@ namespace FlaxEditor.GUI
|
||||
|
||||
PerformLayout();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_columns != null && _splits != null)
|
||||
{
|
||||
Rectangle rect = new Rectangle(0, 0, 0, _headerHeight);
|
||||
for (int i = 0; i < _columns.Length - 1; i++)
|
||||
{
|
||||
rect.Width = GetColumnWidth(i);
|
||||
|
||||
var splitRect = new Rectangle(rect.Right - 2, 2, 4, rect.Height - 4);
|
||||
if (splitRect.Contains(location))
|
||||
{
|
||||
// Start moving splitter
|
||||
Cursor = CursorType.SizeWE;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Cursor = CursorType.Default;
|
||||
}
|
||||
|
||||
rect.X += rect.Width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
base.OnMouseMove(location);
|
||||
}
|
||||
|
||||
@@ -418,9 +418,19 @@ namespace FlaxEditor.GUI.Tabs
|
||||
{
|
||||
// If scroll bar is visible it covers part of the tab header so include this in tab size to improve usability
|
||||
if (_orientation == Orientation.Horizontal && TabsPanel.HScrollBar.Visible)
|
||||
{
|
||||
tabsSize.Y += TabsPanel.HScrollBar.Height;
|
||||
var style = Style.Current;
|
||||
TabsPanel.HScrollBar.TrackColor = style.Background;
|
||||
TabsPanel.HScrollBar.ThumbColor = style.ForegroundGrey;
|
||||
}
|
||||
else if (_orientation == Orientation.Vertical && TabsPanel.VScrollBar.Visible)
|
||||
{
|
||||
tabsSize.X += TabsPanel.VScrollBar.Width;
|
||||
var style = Style.Current;
|
||||
TabsPanel.VScrollBar.TrackColor = style.Background;
|
||||
TabsPanel.VScrollBar.ThumbColor = style.ForegroundGrey;
|
||||
}
|
||||
}
|
||||
|
||||
// Fit the tabs panel
|
||||
|
||||
@@ -130,7 +130,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
/// The keyframes.
|
||||
/// </summary>
|
||||
[EditorDisplay("Keyframes", EditorDisplayAttribute.InlineStyle), ExpandGroups]
|
||||
[Collection(CanReorderItems = false, ReadOnly = true)]
|
||||
[Collection(CanReorderItems = false, CanResize = true)]
|
||||
public List<KeyValuePair<string, object>> Keyframes;
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -159,7 +159,7 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
/// The parameters values.
|
||||
/// </summary>
|
||||
[EditorDisplay("Parameters", EditorDisplayAttribute.InlineStyle), ExpandGroups]
|
||||
[Collection(CanReorderItems = false, ReadOnly = true)]
|
||||
[Collection(CanReorderItems = false, CanResize = true)]
|
||||
public object[] Parameters;
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -363,6 +363,8 @@ namespace FlaxEditor.GUI.Timeline.Tracks
|
||||
/// <inheritdoc />
|
||||
public override void OnDestroy()
|
||||
{
|
||||
if (_previewValue != null)
|
||||
Timeline.ShowPreviewValuesChanged -= OnTimelineShowPreviewValuesChanged;
|
||||
_previewValue = null;
|
||||
_rightKey = null;
|
||||
_addKey = null;
|
||||
|
||||
@@ -698,6 +698,38 @@ namespace FlaxEditor.GUI.Tree
|
||||
}
|
||||
}
|
||||
|
||||
// Show tree guidelines
|
||||
if (Editor.Instance.Options.Options.Interface.ShowTreeLines)
|
||||
{
|
||||
TreeNode parentNode = Parent as TreeNode;
|
||||
bool thisNodeIsLast = false;
|
||||
while (parentNode != null && parentNode != ParentTree.Children[0])
|
||||
{
|
||||
float bottomOffset = 0;
|
||||
float topOffset = 0;
|
||||
|
||||
if (Parent == parentNode && this == Parent.Children[0])
|
||||
topOffset = 2;
|
||||
|
||||
if (thisNodeIsLast && parentNode.Children.Count == 1)
|
||||
bottomOffset = topOffset != 0 ? 4 : 2;
|
||||
|
||||
if (Parent == parentNode && this == Parent.Children[Parent.Children.Count - 1] && !_opened)
|
||||
{
|
||||
thisNodeIsLast = true;
|
||||
bottomOffset = topOffset != 0 ? 4 : 2;
|
||||
}
|
||||
|
||||
float leftOffset = 9;
|
||||
// Adjust offset for icon image
|
||||
if (_iconCollaped.IsValid)
|
||||
leftOffset += 18;
|
||||
var lineRect1 = new Rectangle(parentNode.TextRect.Left - leftOffset, parentNode.HeaderRect.Top + topOffset, 1, parentNode.HeaderRect.Height - bottomOffset);
|
||||
Render2D.FillRectangle(lineRect1, isSelected ? style.ForegroundGrey : style.LightBackground);
|
||||
parentNode = parentNode.Parent as TreeNode;
|
||||
}
|
||||
}
|
||||
|
||||
// Base
|
||||
if (_opened)
|
||||
{
|
||||
@@ -721,15 +753,16 @@ namespace FlaxEditor.GUI.Tree
|
||||
var children = _children;
|
||||
if (children.Count == 0)
|
||||
return;
|
||||
var last = children.Count - 1;
|
||||
|
||||
if (CullChildren)
|
||||
{
|
||||
Render2D.PeekClip(out var globalClipping);
|
||||
Render2D.PeekTransform(out var globalTransform);
|
||||
|
||||
// Try to estimate the rough location of the first node, assuming the node height is constant
|
||||
// Try to estimate the rough location of the first and the last nodes, assuming the node height is constant
|
||||
var firstChildGlobalRect = GetChildGlobalRectangle(children[0], ref globalTransform);
|
||||
var firstVisibleChild = Math.Clamp((int)Math.Floor((globalClipping.Y - firstChildGlobalRect.Top) / firstChildGlobalRect.Height) + 1, 0, children.Count - 1);
|
||||
var firstVisibleChild = Math.Clamp((int)Math.Floor((globalClipping.Top - firstChildGlobalRect.Top) / _headerHeight) + 1, 0, last);
|
||||
if (GetChildGlobalRectangle(children[firstVisibleChild], ref globalTransform).Top > globalClipping.Top || !children[firstVisibleChild].Visible)
|
||||
{
|
||||
// Estimate overshoot, either it's partially visible or hidden in the tree
|
||||
@@ -738,22 +771,29 @@ namespace FlaxEditor.GUI.Tree
|
||||
var child = children[firstVisibleChild];
|
||||
if (!child.Visible)
|
||||
continue;
|
||||
|
||||
if (GetChildGlobalRectangle(child, ref globalTransform).Top < globalClipping.Top)
|
||||
break;
|
||||
}
|
||||
}
|
||||
var lastVisibleChild = Math.Clamp((int)Math.Ceiling((globalClipping.Bottom - firstChildGlobalRect.Top) / _headerHeight) + 1, firstVisibleChild, last);
|
||||
if (GetChildGlobalRectangle(children[lastVisibleChild], ref globalTransform).Top < globalClipping.Bottom || !children[lastVisibleChild].Visible)
|
||||
{
|
||||
// Estimate overshoot, either it's partially visible or hidden in the tree
|
||||
for (; lastVisibleChild < last; lastVisibleChild++)
|
||||
{
|
||||
var child = children[lastVisibleChild];
|
||||
if (!child.Visible)
|
||||
continue;
|
||||
if (GetChildGlobalRectangle(child, ref globalTransform).Top > globalClipping.Bottom)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = firstVisibleChild; i < children.Count; i++)
|
||||
for (int i = firstVisibleChild; i <= lastVisibleChild; i++)
|
||||
{
|
||||
var child = children[i];
|
||||
if (!child.Visible)
|
||||
continue;
|
||||
|
||||
var childGlobalRect = GetChildGlobalRectangle(child, ref globalTransform);
|
||||
if (!globalClipping.Intersects(ref childGlobalRect))
|
||||
break;
|
||||
|
||||
Render2D.PushTransform(ref child._cachedTransform);
|
||||
child.Draw();
|
||||
Render2D.PopTransform();
|
||||
@@ -767,7 +807,7 @@ namespace FlaxEditor.GUI.Tree
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < children.Count; i++)
|
||||
for (int i = 0; i <= last; i++)
|
||||
{
|
||||
var child = children[i];
|
||||
if (child.Visible)
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
using System;
|
||||
using FlaxEngine;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace FlaxEditor.Gizmo
|
||||
{
|
||||
@@ -15,91 +16,120 @@ namespace FlaxEditor.Gizmo
|
||||
[HideInEditor]
|
||||
private sealed class Renderer : PostProcessEffect
|
||||
{
|
||||
private IntPtr _debugDrawContext;
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct Data
|
||||
{
|
||||
public Matrix WorldMatrix;
|
||||
public Matrix ViewProjectionMatrix;
|
||||
public Float4 GridColor;
|
||||
public Float3 ViewPos;
|
||||
public float Far;
|
||||
public Float3 Padding;
|
||||
public float GridSize;
|
||||
}
|
||||
|
||||
private static readonly uint[] _triangles =
|
||||
{
|
||||
0, 2, 1, // Face front
|
||||
1, 3, 0,
|
||||
};
|
||||
|
||||
private GPUBuffer[] _vbs = new GPUBuffer[1];
|
||||
private GPUBuffer _vertexBuffer;
|
||||
private GPUBuffer _indexBuffer;
|
||||
private GPUPipelineState _psGrid;
|
||||
private Shader _shader;
|
||||
|
||||
public Renderer()
|
||||
{
|
||||
Order = -100;
|
||||
UseSingleTarget = true;
|
||||
Location = PostProcessEffectLocation.BeforeForwardPass;
|
||||
Location = PostProcessEffectLocation.Default;
|
||||
_shader = FlaxEngine.Content.LoadAsyncInternal<Shader>("Shaders/Editor/Grid");
|
||||
}
|
||||
|
||||
~Renderer()
|
||||
{
|
||||
if (_debugDrawContext != IntPtr.Zero)
|
||||
{
|
||||
DebugDraw.FreeContext(_debugDrawContext);
|
||||
_debugDrawContext = IntPtr.Zero;
|
||||
}
|
||||
Destroy(ref _psGrid);
|
||||
Destroy(ref _vertexBuffer);
|
||||
Destroy(ref _indexBuffer);
|
||||
_shader = null;
|
||||
}
|
||||
|
||||
public override void Render(GPUContext context, ref RenderContext renderContext, GPUTexture input, GPUTexture output)
|
||||
public override unsafe void Render(GPUContext context, ref RenderContext renderContext, GPUTexture input, GPUTexture output)
|
||||
{
|
||||
if (_shader == null)
|
||||
return;
|
||||
Profiler.BeginEventGPU("Editor Grid");
|
||||
|
||||
if (_debugDrawContext == IntPtr.Zero)
|
||||
_debugDrawContext = DebugDraw.AllocateContext();
|
||||
DebugDraw.SetContext(_debugDrawContext);
|
||||
DebugDraw.UpdateContext(_debugDrawContext, 1.0f / Mathf.Max(Engine.FramesPerSecond, 1));
|
||||
|
||||
var viewPos = (Vector3)renderContext.View.Position;
|
||||
var plane = new Plane(Vector3.Zero, Vector3.UnitY);
|
||||
var dst = CollisionsHelper.DistancePlanePoint(ref plane, ref viewPos);
|
||||
|
||||
var options = Editor.Instance.Options.Options;
|
||||
float space = options.Viewport.ViewportGridScale, size;
|
||||
if (dst <= 500.0f)
|
||||
Float3 camPos = renderContext.View.WorldPosition;
|
||||
float gridSize = renderContext.View.Far + 20000;
|
||||
|
||||
// Lazy-init resources
|
||||
if (_vertexBuffer == null)
|
||||
{
|
||||
size = 8000;
|
||||
_vertexBuffer = new GPUBuffer();
|
||||
var desc = GPUBufferDescription.Vertex(sizeof(Float3), 4);
|
||||
_vertexBuffer.Init(ref desc);
|
||||
}
|
||||
else if (dst <= 2000.0f)
|
||||
if (_indexBuffer == null)
|
||||
{
|
||||
space *= 2;
|
||||
size = 8000;
|
||||
_indexBuffer = new GPUBuffer();
|
||||
fixed (uint* ptr = _triangles)
|
||||
{
|
||||
var desc = GPUBufferDescription.Index(sizeof(uint), _triangles.Length, new IntPtr(ptr));
|
||||
_indexBuffer.Init(ref desc);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (_psGrid == null)
|
||||
{
|
||||
space *= 20;
|
||||
size = 100000;
|
||||
_psGrid = new GPUPipelineState();
|
||||
var desc = GPUPipelineState.Description.Default;
|
||||
desc.BlendMode = BlendingMode.AlphaBlend;
|
||||
desc.CullMode = CullMode.TwoSided;
|
||||
desc.VS = _shader.GPU.GetVS("VS_Grid");
|
||||
desc.PS = _shader.GPU.GetPS("PS_Grid");
|
||||
_psGrid.Init(ref desc);
|
||||
}
|
||||
|
||||
float bigLineIntensity = 0.8f;
|
||||
Color bigColor = Color.Gray * bigLineIntensity;
|
||||
Color color = bigColor * 0.8f;
|
||||
int count = (int)(size / space);
|
||||
int midLine = count / 2;
|
||||
int bigLinesMod = count / 8;
|
||||
|
||||
Vector3 start = new Vector3(0, 0, size * -0.5f);
|
||||
Vector3 end = new Vector3(0, 0, size * 0.5f);
|
||||
|
||||
for (int i = 0; i <= count; i++)
|
||||
// Update vertices of the plane
|
||||
// TODO: perf this operation in a Vertex Shader
|
||||
float y = 1.5f; // Add small bias to reduce Z-fighting with geometry at scene origin
|
||||
var vertices = new Float3[]
|
||||
{
|
||||
start.X = end.X = i * space + start.Z;
|
||||
Color lineColor = color;
|
||||
if (i == midLine)
|
||||
lineColor = Color.Blue * bigLineIntensity;
|
||||
else if (i % bigLinesMod == 0)
|
||||
lineColor = bigColor;
|
||||
DebugDraw.DrawLine(start, end, lineColor);
|
||||
new Float3(-gridSize + camPos.X, y, -gridSize + camPos.Z),
|
||||
new Float3(gridSize + camPos.X, y, gridSize + camPos.Z),
|
||||
new Float3(-gridSize + camPos.X, y, gridSize + camPos.Z),
|
||||
new Float3(gridSize + camPos.X, y, -gridSize + camPos.Z),
|
||||
};
|
||||
fixed (Float3* ptr = vertices)
|
||||
{
|
||||
context.UpdateBuffer(_vertexBuffer, new IntPtr(ptr), (uint)(sizeof(Float3) * vertices.Length));
|
||||
}
|
||||
|
||||
start = new Vector3(size * -0.5f, 0, 0);
|
||||
end = new Vector3(size * 0.5f, 0, 0);
|
||||
|
||||
for (int i = 0; i <= count; i++)
|
||||
// Update constant buffer data
|
||||
var cb = _shader.GPU.GetCB(0);
|
||||
if (cb != IntPtr.Zero)
|
||||
{
|
||||
start.Z = end.Z = i * space + start.X;
|
||||
Color lineColor = color;
|
||||
if (i == midLine)
|
||||
lineColor = Color.Red * bigLineIntensity;
|
||||
else if (i % bigLinesMod == 0)
|
||||
lineColor = bigColor;
|
||||
DebugDraw.DrawLine(start, end, lineColor);
|
||||
var data = new Data();
|
||||
Matrix.Multiply(ref renderContext.View.View, ref renderContext.View.Projection, out var viewProjection);
|
||||
data.WorldMatrix = Matrix.Identity;
|
||||
Matrix.Transpose(ref viewProjection, out data.ViewProjectionMatrix);
|
||||
data.ViewPos = renderContext.View.WorldPosition;
|
||||
data.GridColor = options.Viewport.ViewportGridColor;
|
||||
data.Far = renderContext.View.Far;
|
||||
data.GridSize = options.Viewport.ViewportGridViewDistance;
|
||||
context.UpdateCB(cb, new IntPtr(&data));
|
||||
}
|
||||
|
||||
DebugDraw.Draw(ref renderContext, input.View(), null, true);
|
||||
DebugDraw.SetContext(IntPtr.Zero);
|
||||
// Draw geometry using custom Pixel Shader and Vertex Shader
|
||||
context.BindCB(0, cb);
|
||||
context.BindIB(_indexBuffer);
|
||||
_vbs[0] = _vertexBuffer;
|
||||
context.BindVB(_vbs);
|
||||
context.SetState(_psGrid);
|
||||
context.SetRenderTarget(renderContext.Buffers.DepthBuffer.View(), input.View());
|
||||
context.DrawIndexed((uint)_triangles.Length);
|
||||
|
||||
Profiler.EndEventGPU();
|
||||
}
|
||||
|
||||
@@ -253,7 +253,11 @@ namespace FlaxEditor
|
||||
{
|
||||
// Select node (with additive mode)
|
||||
var selection = new List<SceneGraphNode>();
|
||||
if (Root.GetKey(KeyboardKeys.Control))
|
||||
if (Root.GetKey(KeyboardKeys.Shift) && transformGizmo.Selection.Contains(uiControlNode))
|
||||
{
|
||||
// Move whole selection
|
||||
}
|
||||
else if (Root.GetKey(KeyboardKeys.Control))
|
||||
{
|
||||
// Add/remove from selection
|
||||
selection.AddRange(transformGizmo.Selection);
|
||||
@@ -261,13 +265,14 @@ namespace FlaxEditor
|
||||
selection.Remove(uiControlNode);
|
||||
else
|
||||
selection.Add(uiControlNode);
|
||||
owner.Select(selection);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Select
|
||||
selection.Add(uiControlNode);
|
||||
owner.Select(selection);
|
||||
}
|
||||
owner.Select(selection);
|
||||
|
||||
// Initialize control movement
|
||||
_mouseMovesControl = true;
|
||||
@@ -499,6 +504,15 @@ namespace FlaxEditor
|
||||
bool drawAnySelectedControl = false;
|
||||
var transformGizmo = TransformGizmo;
|
||||
var mousePos = PointFromWindow(RootWindow.MousePosition);
|
||||
if (EnableSelecting && !_mouseMovesControl && !_mouseMovesWidget && IsMouseOver)
|
||||
{
|
||||
// Highlight control under mouse for easier selecting (except if already selected)
|
||||
if (RayCastControl(ref mousePos, out var hitControl) &&
|
||||
(transformGizmo == null || !transformGizmo.Selection.Any(x => x.EditableObject is UIControl controlActor && controlActor.Control == hitControl)))
|
||||
{
|
||||
DrawControl(null, hitControl, false, ref mousePos, ref drawAnySelectedControl);
|
||||
}
|
||||
}
|
||||
if (transformGizmo != null)
|
||||
{
|
||||
// Selected UI controls outline
|
||||
@@ -511,15 +525,6 @@ namespace FlaxEditor
|
||||
}
|
||||
}
|
||||
}
|
||||
if (EnableSelecting && !_mouseMovesControl && !_mouseMovesWidget && IsMouseOver)
|
||||
{
|
||||
// Highlight control under mouse for easier selecting (except if already selected)
|
||||
if (RayCastControl(ref mousePos, out var hitControl) &&
|
||||
(transformGizmo == null || !transformGizmo.Selection.Any(x => x.EditableObject is UIControl controlActor && controlActor.Control == hitControl)))
|
||||
{
|
||||
DrawControl(null, hitControl, false, ref mousePos, ref drawAnySelectedControl);
|
||||
}
|
||||
}
|
||||
if (drawAnySelectedControl)
|
||||
Render2D.PopTransform();
|
||||
|
||||
@@ -617,40 +622,36 @@ namespace FlaxEditor
|
||||
// Draw sizing widgets
|
||||
if (_widgets == null)
|
||||
_widgets = new List<Widget>();
|
||||
var widgetSize = 8.0f;
|
||||
var widgetSize = 10.0f;
|
||||
var viewScale = ViewScale;
|
||||
if (viewScale < 0.7f)
|
||||
widgetSize *= viewScale;
|
||||
var controlSize = control.Size.Absolute.MinValue / 50.0f;
|
||||
if (controlSize < 1.0f)
|
||||
widgetSize *= Mathf.Clamp(controlSize + 0.1f, 0.1f, 1.0f);
|
||||
var cornerSize = new Float2(widgetSize);
|
||||
DrawControlWidget(uiControl, ref ul, ref mousePos, ref cornerSize, new Float2(-1, -1), CursorType.SizeNWSE);
|
||||
DrawControlWidget(uiControl, ref ur, ref mousePos, ref cornerSize, new Float2(1, -1), CursorType.SizeNESW);
|
||||
DrawControlWidget(uiControl, ref bl, ref mousePos, ref cornerSize, new Float2(-1, 1), CursorType.SizeNESW);
|
||||
DrawControlWidget(uiControl, ref br, ref mousePos, ref cornerSize, new Float2(1, 1), CursorType.SizeNWSE);
|
||||
var edgeSizeV = new Float2(widgetSize * 2, widgetSize);
|
||||
var edgeSizeH = new Float2(edgeSizeV.Y, edgeSizeV.X);
|
||||
var widgetHandleSize = new Float2(widgetSize);
|
||||
DrawControlWidget(uiControl, ref ul, ref mousePos, ref widgetHandleSize, viewScale, new Float2(-1, -1), CursorType.SizeNWSE);
|
||||
DrawControlWidget(uiControl, ref ur, ref mousePos, ref widgetHandleSize, viewScale, new Float2(1, -1), CursorType.SizeNESW);
|
||||
DrawControlWidget(uiControl, ref bl, ref mousePos, ref widgetHandleSize, viewScale, new Float2(-1, 1), CursorType.SizeNESW);
|
||||
DrawControlWidget(uiControl, ref br, ref mousePos, ref widgetHandleSize, viewScale, new Float2(1, 1), CursorType.SizeNWSE);
|
||||
Float2.Lerp(ref ul, ref bl, 0.5f, out var el);
|
||||
Float2.Lerp(ref ur, ref br, 0.5f, out var er);
|
||||
Float2.Lerp(ref ul, ref ur, 0.5f, out var eu);
|
||||
Float2.Lerp(ref bl, ref br, 0.5f, out var eb);
|
||||
DrawControlWidget(uiControl, ref el, ref mousePos, ref edgeSizeH, new Float2(-1, 0), CursorType.SizeWE);
|
||||
DrawControlWidget(uiControl, ref er, ref mousePos, ref edgeSizeH, new Float2(1, 0), CursorType.SizeWE);
|
||||
DrawControlWidget(uiControl, ref eu, ref mousePos, ref edgeSizeV, new Float2(0, -1), CursorType.SizeNS);
|
||||
DrawControlWidget(uiControl, ref eb, ref mousePos, ref edgeSizeV, new Float2(0, 1), CursorType.SizeNS);
|
||||
DrawControlWidget(uiControl, ref el, ref mousePos, ref widgetHandleSize, viewScale, new Float2(-1, 0), CursorType.SizeWE);
|
||||
DrawControlWidget(uiControl, ref er, ref mousePos, ref widgetHandleSize, viewScale, new Float2(1, 0), CursorType.SizeWE);
|
||||
DrawControlWidget(uiControl, ref eu, ref mousePos, ref widgetHandleSize, viewScale, new Float2(0, -1), CursorType.SizeNS);
|
||||
DrawControlWidget(uiControl, ref eb, ref mousePos, ref widgetHandleSize, viewScale, new Float2(0, 1), CursorType.SizeNS);
|
||||
|
||||
// TODO: draw anchors
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawControlWidget(UIControl uiControl, ref Float2 pos, ref Float2 mousePos, ref Float2 size, Float2 resizeAxis, CursorType cursor)
|
||||
private void DrawControlWidget(UIControl uiControl, ref Float2 pos, ref Float2 mousePos, ref Float2 size, float scale, Float2 resizeAxis, CursorType cursor)
|
||||
{
|
||||
var style = Style.Current;
|
||||
var rect = new Rectangle(pos - size * 0.5f, size);
|
||||
var rect = new Rectangle((pos + resizeAxis * 10 * scale) - size * 0.5f, size);
|
||||
if (rect.Contains(ref mousePos))
|
||||
{
|
||||
Render2D.FillRectangle(rect, style.Foreground);
|
||||
Render2D.DrawRectangle(rect, style.SelectionBorder);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -433,6 +433,9 @@ DEFINE_INTERNAL_CALL(void) EditorInternal_RunVisualScriptBreakpointLoopTick(floa
|
||||
case InputDevice::EventType::MouseMove:
|
||||
window->OnMouseMove(window->ScreenToClient(e.MouseData.Position));
|
||||
break;
|
||||
case InputDevice::EventType::MouseMoveRelative:
|
||||
window->OnMouseMoveRelative(e.MouseMovementData.PositionRelative);
|
||||
break;
|
||||
case InputDevice::EventType::MouseLeave:
|
||||
window->OnMouseLeave();
|
||||
break;
|
||||
|
||||
@@ -223,6 +223,19 @@ void ManagedEditor::Init()
|
||||
{
|
||||
LOG(Info, "Loading managed assemblies (due to disabled compilation on startup)");
|
||||
Scripting::Load();
|
||||
|
||||
const auto endInitMethod = mclass->GetMethod("EndInit");
|
||||
if (endInitMethod == nullptr)
|
||||
{
|
||||
LOG(Fatal, "Invalid Editor assembly! Missing EndInit method.");
|
||||
}
|
||||
endInitMethod->Invoke(instance, nullptr, &exception);
|
||||
if (exception)
|
||||
{
|
||||
MException ex(exception);
|
||||
ex.Log(LogType::Warning, TEXT("ManagedEditor::EndInit"));
|
||||
LOG_STR(Fatal, TEXT("Failed to initialize editor during EndInit! ") + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
// Call building if need to (based on CL)
|
||||
|
||||
@@ -27,6 +27,7 @@ API_CLASS(Namespace="FlaxEditor", Name="Editor", NoSpawn, NoConstructor) class M
|
||||
byte AutoReloadScriptsOnMainWindowFocus = 1;
|
||||
byte ForceScriptCompilationOnStartup = 1;
|
||||
byte UseAssetImportPathRelative = 1;
|
||||
byte EnableParticlesPreview = 1;
|
||||
byte AutoRebuildCSG = 1;
|
||||
float AutoRebuildCSGTimeoutMs = 50;
|
||||
byte AutoRebuildNavMesh = 1;
|
||||
|
||||
@@ -228,7 +228,7 @@ namespace FlaxEditor.Modules
|
||||
new SearchResult { Name = item.ShortName, Type = assetItem.TypeName, Item = item }
|
||||
};
|
||||
}
|
||||
var actor = FlaxEngine.Object.Find<Actor>(ref id);
|
||||
var actor = FlaxEngine.Object.Find<Actor>(ref id, true);
|
||||
if (actor != null)
|
||||
{
|
||||
return new List<SearchResult>
|
||||
@@ -236,6 +236,16 @@ namespace FlaxEditor.Modules
|
||||
new SearchResult { Name = actor.Name, Type = actor.TypeName, Item = actor }
|
||||
};
|
||||
}
|
||||
var script = FlaxEngine.Object.Find<Script>(ref id, true);
|
||||
if (script != null && script.Actor != null)
|
||||
{
|
||||
string actorPathStart = $"{script.Actor.Name}/";
|
||||
|
||||
return new List<SearchResult>
|
||||
{
|
||||
new SearchResult { Name = $"{actorPathStart}{script.TypeName}", Type = script.TypeName, Item = script }
|
||||
};
|
||||
}
|
||||
}
|
||||
Profiler.BeginEvent("ContentFinding.Search");
|
||||
|
||||
@@ -332,9 +342,10 @@ namespace FlaxEditor.Modules
|
||||
{
|
||||
foreach (var contentItem in items)
|
||||
{
|
||||
var name = contentItem.ShortName;
|
||||
if (contentItem.IsAsset)
|
||||
{
|
||||
if (nameRegex.Match(contentItem.ShortName).Success)
|
||||
if (nameRegex.Match(name).Success)
|
||||
{
|
||||
var asset = contentItem as AssetItem;
|
||||
if (asset == null || !typeRegex.Match(asset.TypeName).Success)
|
||||
@@ -348,7 +359,7 @@ namespace FlaxEditor.Modules
|
||||
var splits = asset.TypeName.Split('.');
|
||||
finalName = splits[splits.Length - 1];
|
||||
}
|
||||
matches.Add(new SearchResult { Name = asset.ShortName, Type = finalName, Item = asset });
|
||||
matches.Add(new SearchResult { Name = name, Type = finalName, Item = asset });
|
||||
}
|
||||
}
|
||||
else if (contentItem.IsFolder)
|
||||
@@ -360,11 +371,12 @@ namespace FlaxEditor.Modules
|
||||
}
|
||||
else
|
||||
{
|
||||
if (nameRegex.Match(contentItem.ShortName).Success && typeRegex.Match(contentItem.GetType().Name).Success)
|
||||
if (nameRegex.Match(name).Success && typeRegex.Match(contentItem.GetType().Name).Success)
|
||||
{
|
||||
string finalName = contentItem.GetType().Name.Replace("Item", "");
|
||||
|
||||
matches.Add(new SearchResult { Name = contentItem.ShortName, Type = finalName, Item = contentItem });
|
||||
if (contentItem is ScriptItem)
|
||||
name = contentItem.FileName; // Show extension for scripts (esp. for .h and .cpp files of the same name)
|
||||
matches.Add(new SearchResult { Name = name, Type = finalName, Item = contentItem });
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -388,6 +400,13 @@ namespace FlaxEditor.Modules
|
||||
Editor.Instance.SceneEditing.Select(actor);
|
||||
Editor.Instance.Windows.EditWin.Viewport.FocusSelection();
|
||||
break;
|
||||
case Script script:
|
||||
if (script.Actor != null)
|
||||
{
|
||||
Editor.Instance.SceneEditing.Select(script.Actor);
|
||||
Editor.Instance.Windows.EditWin.Viewport.FocusSelection();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -202,6 +202,7 @@ namespace FlaxEditor.Modules
|
||||
|
||||
var prefabId = ((ActorNode)selection[0]).Actor.PrefabID;
|
||||
var prefab = FlaxEngine.Content.LoadAsync<Prefab>(prefabId);
|
||||
Editor.Windows.ContentWin.ClearItemsSearch();
|
||||
Editor.Windows.ContentWin.Select(prefab);
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using FlaxEngine;
|
||||
|
||||
namespace FlaxEditor.Modules
|
||||
@@ -119,6 +121,30 @@ namespace FlaxEditor.Modules
|
||||
return _customData.TryGetValue(key, out value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the custom data by the key.
|
||||
/// </summary>
|
||||
/// <param name="key">The key.</param>
|
||||
/// <param name="value">When this method returns, contains the value associated with the specified key, if the key is found; otherwise, the default value for the type of the <paramref name="value" /> parameter. This parameter is passed uninitialized.</param>
|
||||
/// <returns>The custom data.</returns>
|
||||
public bool TryGetCustomData(string key, out bool value)
|
||||
{
|
||||
value = false;
|
||||
return _customData.TryGetValue(key, out var valueStr) && bool.TryParse(valueStr, out value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the custom data by the key.
|
||||
/// </summary>
|
||||
/// <param name="key">The key.</param>
|
||||
/// <param name="value">When this method returns, contains the value associated with the specified key, if the key is found; otherwise, the default value for the type of the <paramref name="value" /> parameter. This parameter is passed uninitialized.</param>
|
||||
/// <returns>The custom data.</returns>
|
||||
public bool TryGetCustomData(string key, out float value)
|
||||
{
|
||||
value = 0.0f;
|
||||
return _customData.TryGetValue(key, out var valueStr) && float.TryParse(valueStr, out value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the custom data.
|
||||
/// </summary>
|
||||
@@ -130,6 +156,28 @@ namespace FlaxEditor.Modules
|
||||
_isDirty = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the custom data.
|
||||
/// </summary>
|
||||
/// <param name="key">The key.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void SetCustomData(string key, bool value)
|
||||
{
|
||||
SetCustomData(key, value.ToString());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the custom data.
|
||||
/// </summary>
|
||||
/// <param name="key">The key.</param>
|
||||
/// <param name="value">The value.</param>
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public void SetCustomData(string key, float value)
|
||||
{
|
||||
SetCustomData(key, value.ToString(CultureInfo.InvariantCulture));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the custom data.
|
||||
/// </summary>
|
||||
|
||||
@@ -182,6 +182,9 @@ namespace FlaxEditor.Modules
|
||||
var cam = scene.AddChild<Camera>();
|
||||
cam.Name = "Camera";
|
||||
cam.Position = new Vector3(0, 150, -300);
|
||||
//
|
||||
var audioListener = cam.AddChild<AudioListener>();
|
||||
audioListener.Name = "Audio Listener";
|
||||
|
||||
// Serialize
|
||||
var bytes = Level.SaveSceneToBytes(scene);
|
||||
|
||||
@@ -127,13 +127,12 @@ namespace FlaxEditor.Modules
|
||||
public void RequestStartPlayGame()
|
||||
{
|
||||
if (!Editor.StateMachine.IsEditMode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var firstScene = Content.Settings.GameSettings.Load().FirstScene;
|
||||
if (firstScene == Guid.Empty)
|
||||
{
|
||||
Editor.LogWarning("No First Scene assigned in Game Settings.");
|
||||
if (Level.IsAnySceneLoaded)
|
||||
Editor.Simulation.RequestStartPlayScenes();
|
||||
return;
|
||||
@@ -141,6 +140,9 @@ namespace FlaxEditor.Modules
|
||||
if (!FlaxEngine.Content.GetAssetInfo(firstScene.ID, out var info))
|
||||
{
|
||||
Editor.LogWarning("Invalid First Scene in Game Settings.");
|
||||
if (Level.IsAnySceneLoaded)
|
||||
Editor.Simulation.RequestStartPlayScenes();
|
||||
return;
|
||||
}
|
||||
|
||||
// Load scenes after entering the play mode
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Xml;
|
||||
using FlaxEditor.Scripting;
|
||||
@@ -65,7 +66,7 @@ namespace FlaxEditor.Modules.SourceCodeEditing
|
||||
{
|
||||
var key = "T:" + GetXmlKey(type.Type.FullName);
|
||||
if (xml.TryGetValue(key, out var xmlDoc))
|
||||
text += '\n' + xmlDoc;
|
||||
text += '\n' + FilterWhitespaces(xmlDoc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,6 +263,27 @@ namespace FlaxEditor.Modules.SourceCodeEditing
|
||||
return Regex.Replace(typeFullNameString, @"\[.*\]", string.Empty).Replace('+', '.');
|
||||
}
|
||||
|
||||
private static string FilterWhitespaces(string str)
|
||||
{
|
||||
if (str.Contains(" ", StringComparison.Ordinal))
|
||||
{
|
||||
var sb = new StringBuilder();
|
||||
var prev = str[0];
|
||||
sb.Append(prev);
|
||||
for (int i = 1; i < str.Length; i++)
|
||||
{
|
||||
var c = str[i];
|
||||
if (prev != ' ' || c != ' ')
|
||||
{
|
||||
sb.Append(c);
|
||||
}
|
||||
prev = c;
|
||||
}
|
||||
str = sb.ToString();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
private Dictionary<string, string> GetXmlDocs(Assembly assembly)
|
||||
{
|
||||
if (!_xmlCache.TryGetValue(assembly, out var result))
|
||||
|
||||
@@ -381,7 +381,7 @@ namespace FlaxEditor.Modules
|
||||
Editor.Options.OptionsChanged += OnOptionsChanged;
|
||||
|
||||
// Add dummy control for drawing the main window borders if using a custom style
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
||||
if (!Editor.Options.Options.Interface.UseNativeWindowSystem)
|
||||
#endif
|
||||
{
|
||||
@@ -565,6 +565,7 @@ namespace FlaxEditor.Modules
|
||||
if (item != null)
|
||||
Editor.ContentEditing.Open(item);
|
||||
});
|
||||
cm.AddButton("Editor Options", () => Editor.Windows.EditorOptionsWin.Show());
|
||||
|
||||
// Scene
|
||||
MenuScene = MainMenu.AddButton("Scene");
|
||||
@@ -619,7 +620,6 @@ namespace FlaxEditor.Modules
|
||||
_menuToolsTakeScreenshot = cm.AddButton("Take screenshot", inputOptions.TakeScreenshot, Editor.Windows.TakeScreenshot);
|
||||
cm.AddSeparator();
|
||||
cm.AddButton("Plugins", () => Editor.Windows.PluginsWin.Show());
|
||||
cm.AddButton("Options", () => Editor.Windows.EditorOptionsWin.Show());
|
||||
|
||||
// Window
|
||||
MenuWindow = MainMenu.AddButton("Window");
|
||||
|
||||
@@ -511,11 +511,11 @@ namespace FlaxEditor.Modules
|
||||
{
|
||||
var bounds = node["Bounds"];
|
||||
var isMaximizedText = bounds.GetAttribute("IsMaximized");
|
||||
if (!string.IsNullOrEmpty(isMaximizedText))
|
||||
isMaximized = bool.Parse(isMaximizedText);
|
||||
if (!string.IsNullOrEmpty(isMaximizedText) && bool.TryParse(isMaximizedText, out var tmpBool))
|
||||
isMaximized = tmpBool;
|
||||
var isMinimizedText = bounds.GetAttribute("IsMinimized");
|
||||
if (!string.IsNullOrEmpty(isMinimizedText))
|
||||
isMinimized = bool.Parse(isMinimizedText);
|
||||
if (!string.IsNullOrEmpty(isMinimizedText) && bool.TryParse(isMinimizedText, out tmpBool))
|
||||
isMinimized = tmpBool;
|
||||
float x = float.Parse(bounds.GetAttribute("X"), CultureInfo.InvariantCulture);
|
||||
float y = float.Parse(bounds.GetAttribute("Y"), CultureInfo.InvariantCulture);
|
||||
float width = float.Parse(bounds.GetAttribute("Width"), CultureInfo.InvariantCulture);
|
||||
@@ -760,8 +760,10 @@ namespace FlaxEditor.Modules
|
||||
{
|
||||
settings.HasBorder = false;
|
||||
|
||||
#if !PLATFORM_SDL
|
||||
// Skip OS sizing frame and implement it using LeftButtonHit
|
||||
settings.HasSizingFrame = false;
|
||||
#endif
|
||||
}
|
||||
#elif PLATFORM_LINUX
|
||||
settings.HasBorder = false;
|
||||
|
||||
@@ -145,7 +145,7 @@ namespace FlaxEditor.Options
|
||||
[EditorDisplay("Interface"), EditorOrder(10), Tooltip("Editor User Interface scale. Applied to all UI elements, windows and text. Can be used to scale the interface up on a bigger display. Editor restart required.")]
|
||||
public float InterfaceScale { get; set; } = 1.0f;
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
#if PLATFORM_WINDOWS || PLATFORM_SDL
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether use native window title bar. Editor restart required.
|
||||
/// </summary>
|
||||
@@ -175,13 +175,6 @@ namespace FlaxEditor.Options
|
||||
[EditorDisplay("Interface", "New Window Location"), EditorOrder(150), Tooltip("Define the opening method for new windows, open in a new tab by default.")]
|
||||
public DockStateProxy NewWindowLocation { get; set; } = DockStateProxy.Float;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the timestamps prefix mode for debug log messages.
|
||||
/// </summary>
|
||||
[DefaultValue(TimestampsFormats.None)]
|
||||
[EditorDisplay("Interface"), EditorOrder(210), Tooltip("The timestamps prefix mode for debug log messages.")]
|
||||
public TimestampsFormats DebugLogTimestampsFormat { get; set; } = TimestampsFormats.None;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the editor icons scale. Editor restart required.
|
||||
/// </summary>
|
||||
@@ -196,6 +189,13 @@ namespace FlaxEditor.Options
|
||||
[EditorDisplay("Interface"), EditorOrder(280), Tooltip("Editor content window orientation.")]
|
||||
public FlaxEngine.GUI.Orientation ContentWindowOrientation { get; set; } = FlaxEngine.GUI.Orientation.Horizontal;
|
||||
|
||||
/// <summary>
|
||||
/// If checked, color pickers will always modify the color unless 'Cancel' if pressed, otherwise color won't change unless 'Ok' is pressed.
|
||||
/// </summary>
|
||||
[DefaultValue(true)]
|
||||
[EditorDisplay("Interface"), EditorOrder(290)]
|
||||
public bool AutoAcceptColorPickerChange { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the formatting option for numeric values in the editor.
|
||||
/// </summary>
|
||||
@@ -211,23 +211,79 @@ namespace FlaxEditor.Options
|
||||
public bool SeparateValueAndUnit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the timestamps prefix mode for output log messages.
|
||||
/// Gets or sets the option to put a space between numbers and units for unit formatting.
|
||||
/// </summary>
|
||||
[DefaultValue(TimestampsFormats.TimeSinceStartup)]
|
||||
[EditorDisplay("Output Log", "Timestamps Format"), EditorOrder(300), Tooltip("The timestamps prefix mode for output log messages.")]
|
||||
public TimestampsFormats OutputLogTimestampsFormat { get; set; } = TimestampsFormats.TimeSinceStartup;
|
||||
[DefaultValue(true)]
|
||||
[EditorDisplay("Interface"), EditorOrder(320)]
|
||||
public bool ShowTreeLines { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the timestamps prefix mode for output log messages.
|
||||
/// </summary>
|
||||
[DefaultValue(TimestampsFormats.None)]
|
||||
[EditorDisplay("Debug Log"), EditorOrder(350), Tooltip("The timestamps prefix mode for debug log messages.")]
|
||||
public TimestampsFormats DebugLogTimestampsFormat { get; set; } = TimestampsFormats.None;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the clear on play for debug log messages.
|
||||
/// </summary>
|
||||
[DefaultValue(true)]
|
||||
[EditorDisplay("Output Log", "Show Log Type"), EditorOrder(310), Tooltip("Determines whether show log type prefix in output log messages.")]
|
||||
[EditorDisplay("Debug Log", "Clear on Play"), EditorOrder(360), Tooltip("Clears all log entries on enter playmode.")]
|
||||
public bool DebugLogClearOnPlay { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the collapse mode for debug log messages.
|
||||
/// </summary>
|
||||
[DefaultValue(true)]
|
||||
[EditorDisplay("Debug Log"), EditorOrder(361), Tooltip("Collapses similar or repeating log entries.")]
|
||||
public bool DebugLogCollapse { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the automatic pause on error for debug log messages.
|
||||
/// </summary>
|
||||
[DefaultValue(false)]
|
||||
[EditorDisplay("Debug Log", "Pause on Error"), EditorOrder(362), Tooltip("Performs auto pause on error.")]
|
||||
public bool DebugLogPauseOnError { get; set; } = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the automatic pause on error for debug log messages.
|
||||
/// </summary>
|
||||
[DefaultValue(true)]
|
||||
[EditorDisplay("Debug Log", "Show error messages"), EditorOrder(370), Tooltip("Shows/hides error messages.")]
|
||||
public bool DebugLogShowErrorMessages { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the automatic pause on error for debug log messages.
|
||||
/// </summary>
|
||||
[DefaultValue(true)]
|
||||
[EditorDisplay("Debug Log", "Show warning messages"), EditorOrder(371), Tooltip("Shows/hides warning messages.")]
|
||||
public bool DebugLogShowWarningMessages { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the automatic pause on error for debug log messages.
|
||||
/// </summary>
|
||||
[DefaultValue(true)]
|
||||
[EditorDisplay("Debug Log", "Show info messages"), EditorOrder(372), Tooltip("Shows/hides info messages.")]
|
||||
public bool DebugLogShowInfoMessages { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the timestamps prefix mode for output log messages.
|
||||
/// </summary>
|
||||
[DefaultValue(TimestampsFormats.TimeSinceStartup)]
|
||||
[EditorDisplay("Output Log", "Timestamps Format"), EditorOrder(400), Tooltip("The timestamps prefix mode for output log messages.")]
|
||||
public TimestampsFormats OutputLogTimestampsFormat { get; set; } = TimestampsFormats.TimeSinceStartup;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the log type prefix mode for output log messages.
|
||||
/// </summary>
|
||||
[DefaultValue(true)]
|
||||
[EditorDisplay("Output Log", "Show Log Type"), EditorOrder(410), Tooltip("Determines whether show log type prefix in output log messages.")]
|
||||
public bool OutputLogShowLogType { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the output log text font.
|
||||
/// </summary>
|
||||
[EditorDisplay("Output Log", "Text Font"), EditorOrder(320), Tooltip("The output log text font.")]
|
||||
[EditorDisplay("Output Log", "Text Font"), EditorOrder(420), Tooltip("The output log text font.")]
|
||||
public FontReference OutputLogTextFont
|
||||
{
|
||||
get => _outputLogFont;
|
||||
@@ -246,65 +302,79 @@ namespace FlaxEditor.Options
|
||||
/// Gets or sets the output log text color.
|
||||
/// </summary>
|
||||
[DefaultValue(typeof(Color), "1,1,1,1")]
|
||||
[EditorDisplay("Output Log", "Text Color"), EditorOrder(330), Tooltip("The output log text color.")]
|
||||
[EditorDisplay("Output Log", "Text Color"), EditorOrder(430), Tooltip("The output log text color.")]
|
||||
public Color OutputLogTextColor { get; set; } = Color.White;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the output log text shadow color.
|
||||
/// </summary>
|
||||
[DefaultValue(typeof(Color), "0,0,0,0.5")]
|
||||
[EditorDisplay("Output Log", "Text Shadow Color"), EditorOrder(340), Tooltip("The output log text shadow color.")]
|
||||
[EditorDisplay("Output Log", "Text Shadow Color"), EditorOrder(440), Tooltip("The output log text shadow color.")]
|
||||
public Color OutputLogTextShadowColor { get; set; } = new Color(0, 0, 0, 0.5f);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the output log text shadow offset. Set to 0 to disable this feature.
|
||||
/// </summary>
|
||||
[DefaultValue(typeof(Float2), "1,1")]
|
||||
[EditorDisplay("Output Log", "Text Shadow Offset"), EditorOrder(340), Tooltip("The output log text shadow offset. Set to 0 to disable this feature.")]
|
||||
[EditorDisplay("Output Log", "Text Shadow Offset"), EditorOrder(445), Tooltip("The output log text shadow offset. Set to 0 to disable this feature.")]
|
||||
public Float2 OutputLogTextShadowOffset { get; set; } = new Float2(1);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether auto-focus output log window on code compilation error.
|
||||
/// </summary>
|
||||
[DefaultValue(true)]
|
||||
[EditorDisplay("Output Log", "Focus Output Log On Compilation Error"), EditorOrder(350), Tooltip("Determines whether auto-focus output log window on code compilation error.")]
|
||||
[EditorDisplay("Output Log", "Focus Output Log On Compilation Error"), EditorOrder(450), Tooltip("Determines whether auto-focus output log window on code compilation error.")]
|
||||
public bool FocusOutputLogOnCompilationError { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether auto-focus output log window on game build error.
|
||||
/// </summary>
|
||||
[DefaultValue(true)]
|
||||
[EditorDisplay("Output Log", "Focus Output Log On Game Build Error"), EditorOrder(360), Tooltip("Determines whether auto-focus output log window on game build error.")]
|
||||
[EditorDisplay("Output Log", "Focus Output Log On Game Build Error"), EditorOrder(460), Tooltip("Determines whether auto-focus output log window on game build error.")]
|
||||
public bool FocusOutputLogOnGameBuildError { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the value for automatic scroll to bottom in output log.
|
||||
/// </summary>
|
||||
[DefaultValue(true)]
|
||||
[EditorDisplay("Output Log", "Scroll to bottom"), EditorOrder(470), Tooltip("Scroll the output log view to bottom automatically after new lines are added.")]
|
||||
public bool OutputLogScrollToBottom { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether auto-focus game window on play mode start.
|
||||
/// </summary>
|
||||
[DefaultValue(true)]
|
||||
[EditorDisplay("Play In-Editor", "Focus Game Window On Play"), EditorOrder(400), Tooltip("Determines whether auto-focus game window on play mode start.")]
|
||||
[EditorDisplay("Play In-Editor", "Focus Game Window On Play"), EditorOrder(500), Tooltip("Determines whether auto-focus game window on play mode start.")]
|
||||
public bool FocusGameWinOnPlay { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating what action should be taken upon pressing the play button.
|
||||
/// </summary>
|
||||
[DefaultValue(PlayAction.PlayScenes)]
|
||||
[EditorDisplay("Play In-Editor", "Play Button Action"), EditorOrder(410)]
|
||||
[EditorDisplay("Play In-Editor", "Play Button Action"), EditorOrder(510)]
|
||||
public PlayAction PlayButtonAction { get; set; } = PlayAction.PlayScenes;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating how the game window should be displayed when the game is launched.
|
||||
/// </summary>
|
||||
[DefaultValue(GameWindowMode.Docked)]
|
||||
[EditorDisplay("Play In-Editor", "Game Window Mode"), EditorOrder(420), Tooltip("Determines how the game window is displayed when the game is launched.")]
|
||||
[EditorDisplay("Play In-Editor", "Game Window Mode"), EditorOrder(520), Tooltip("Determines how the game window is displayed when the game is launched.")]
|
||||
public GameWindowMode DefaultGameWindowMode { get; set; } = GameWindowMode.Docked;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating the number of game clients to launch when building and/or running cooked game.
|
||||
/// </summary>
|
||||
[DefaultValue(1), Range(1, 4)]
|
||||
[EditorDisplay("Cook & Run"), EditorOrder(500)]
|
||||
[EditorDisplay("Cook & Run"), EditorOrder(600)]
|
||||
public int NumberOfGameClientsToLaunch = 1;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the visject connection curvature.
|
||||
/// </summary>
|
||||
[DefaultValue(1.0f), Range(0.0f, 2.0f)]
|
||||
[EditorDisplay("Visject"), EditorOrder(550)]
|
||||
public float ConnectionCurvature { get; set; } = 1.0f;
|
||||
|
||||
private static FontAsset DefaultFont => FlaxEngine.Content.LoadAsyncInternal<FontAsset>(EditorAssets.PrimaryFont);
|
||||
private static FontAsset ConsoleFont => FlaxEngine.Content.LoadAsyncInternal<FontAsset>(EditorAssets.InconsolataRegularFont);
|
||||
|
||||
@@ -317,13 +387,13 @@ namespace FlaxEditor.Options
|
||||
/// <summary>
|
||||
/// The list of fallback fonts to use when main text font is missing certain characters. Empty to use fonts from GraphicsSettings.
|
||||
/// </summary>
|
||||
[EditorDisplay("Fonts"), EditorOrder(650)]
|
||||
[EditorDisplay("Fonts"), EditorOrder(750)]
|
||||
public FontAsset[] FallbackFonts = new FontAsset[1] { FlaxEngine.Content.LoadAsyncInternal<FontAsset>(EditorAssets.FallbackFont) };
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the title font for editor UI.
|
||||
/// </summary>
|
||||
[EditorDisplay("Fonts"), EditorOrder(600), Tooltip("The title font for editor UI.")]
|
||||
[EditorDisplay("Fonts"), EditorOrder(700), Tooltip("The title font for editor UI.")]
|
||||
public FontReference TitleFont
|
||||
{
|
||||
get => _titleFont;
|
||||
@@ -341,7 +411,7 @@ namespace FlaxEditor.Options
|
||||
/// <summary>
|
||||
/// Gets or sets the large font for editor UI.
|
||||
/// </summary>
|
||||
[EditorDisplay("Fonts"), EditorOrder(610), Tooltip("The large font for editor UI.")]
|
||||
[EditorDisplay("Fonts"), EditorOrder(710), Tooltip("The large font for editor UI.")]
|
||||
public FontReference LargeFont
|
||||
{
|
||||
get => _largeFont;
|
||||
@@ -359,7 +429,7 @@ namespace FlaxEditor.Options
|
||||
/// <summary>
|
||||
/// Gets or sets the medium font for editor UI.
|
||||
/// </summary>
|
||||
[EditorDisplay("Fonts"), EditorOrder(620), Tooltip("The medium font for editor UI.")]
|
||||
[EditorDisplay("Fonts"), EditorOrder(720), Tooltip("The medium font for editor UI.")]
|
||||
public FontReference MediumFont
|
||||
{
|
||||
get => _mediumFont;
|
||||
@@ -377,7 +447,7 @@ namespace FlaxEditor.Options
|
||||
/// <summary>
|
||||
/// Gets or sets the small font for editor UI.
|
||||
/// </summary>
|
||||
[EditorDisplay("Fonts"), EditorOrder(630), Tooltip("The small font for editor UI.")]
|
||||
[EditorDisplay("Fonts"), EditorOrder(730), Tooltip("The small font for editor UI.")]
|
||||
public FontReference SmallFont
|
||||
{
|
||||
get => _smallFont;
|
||||
|
||||
@@ -192,6 +192,7 @@ namespace FlaxEditor.Options
|
||||
internalOptions.AutoReloadScriptsOnMainWindowFocus = (byte)(Options.General.AutoReloadScriptsOnMainWindowFocus ? 1 : 0);
|
||||
internalOptions.ForceScriptCompilationOnStartup = (byte)(Options.General.ForceScriptCompilationOnStartup ? 1 : 0);
|
||||
internalOptions.UseAssetImportPathRelative = (byte)(Options.General.UseAssetImportPathRelative ? 1 : 0);
|
||||
internalOptions.EnableParticlesPreview = (byte)(Options.Visual.EnableParticlesPreview ? 1 : 0);
|
||||
internalOptions.AutoRebuildCSG = (byte)(Options.General.AutoRebuildCSG ? 1 : 0);
|
||||
internalOptions.AutoRebuildCSGTimeoutMs = Options.General.AutoRebuildCSGTimeoutMs;
|
||||
internalOptions.AutoRebuildNavMesh = (byte)(Options.General.AutoRebuildNavMesh ? 1 : 0);
|
||||
@@ -255,6 +256,17 @@ namespace FlaxEditor.Options
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure custom fonts are valid, reset if not
|
||||
var defaultInterfaceOptions = new InterfaceOptions();
|
||||
if (Style.Current.FontTitle == null)
|
||||
Style.Current.FontTitle = defaultInterfaceOptions.TitleFont.GetFont();
|
||||
if (Style.Current.FontSmall == null)
|
||||
Style.Current.FontSmall = defaultInterfaceOptions.SmallFont.GetFont();
|
||||
if (Style.Current.FontMedium == null)
|
||||
Style.Current.FontMedium = defaultInterfaceOptions.MediumFont.GetFont();
|
||||
if (Style.Current.FontLarge == null)
|
||||
Style.Current.FontLarge = defaultInterfaceOptions.LargeFont.GetFont();
|
||||
|
||||
// Set fallback fonts
|
||||
var fallbackFonts = Options.Interface.FallbackFonts;
|
||||
if (fallbackFonts == null || fallbackFonts.Length == 0 || fallbackFonts.All(x => x == null))
|
||||
|
||||
@@ -129,5 +129,19 @@ namespace FlaxEditor.Options
|
||||
[DefaultValue(50.0f), Limit(25.0f, 500.0f, 5.0f)]
|
||||
[EditorDisplay("Defaults"), EditorOrder(220), Tooltip("The default editor viewport grid scale.")]
|
||||
public float ViewportGridScale { get; set; } = 50.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the view distance you can see the grid.
|
||||
/// </summary>
|
||||
[DefaultValue(2500.0f)]
|
||||
[EditorDisplay("Grid"), EditorOrder(300), Tooltip("The maximum distance you will be able to see the grid.")]
|
||||
public float ViewportGridViewDistance { get; set; } = 2500.0f;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the grid color.
|
||||
/// </summary>
|
||||
[DefaultValue(typeof(Color), "0.5,0.5,0.5,1.0")]
|
||||
[EditorDisplay("Grid"), EditorOrder(310), Tooltip("The color for the viewport grid.")]
|
||||
public Color ViewportGridColor { get; set; } = new Color(0.5f, 0.5f, 0.5f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,5 +59,12 @@ namespace FlaxEditor.Options
|
||||
[DefaultValue(true)]
|
||||
[EditorDisplay("Quality", "Enable MSAA For Debug Draw"), EditorOrder(500), Tooltip("Determines whether enable MSAA for DebugDraw primitives rendering. Helps with pixel aliasing but reduces performance.")]
|
||||
public bool EnableMSAAForDebugDraw { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether show looping particle effects in Editor viewport to simulate in-game look.
|
||||
/// </summary>
|
||||
[DefaultValue(true)]
|
||||
[EditorDisplay("Preview"), EditorOrder(1000)]
|
||||
public bool EnableParticlesPreview { get; set; } = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ using FlaxEditor.Windows.Assets;
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using FlaxEngine.Utilities;
|
||||
using Object = FlaxEngine.Object;
|
||||
|
||||
namespace FlaxEditor.SceneGraph.GUI
|
||||
{
|
||||
@@ -355,7 +356,7 @@ namespace FlaxEditor.SceneGraph.GUI
|
||||
private void OnRenamed(RenamePopup renamePopup)
|
||||
{
|
||||
using (new UndoBlock(ActorNode.Root.Undo, Actor, "Rename"))
|
||||
Actor.Name = renamePopup.Text;
|
||||
Actor.Name = renamePopup.Text.Trim();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -625,6 +626,7 @@ namespace FlaxEditor.SceneGraph.GUI
|
||||
{
|
||||
var item = _dragScriptItems.Objects[i];
|
||||
var actorType = Editor.Instance.CodeEditing.Actors.Get(item);
|
||||
var scriptType = Editor.Instance.CodeEditing.Scripts.Get(item);
|
||||
if (actorType != ScriptType.Null)
|
||||
{
|
||||
var actor = actorType.CreateInstance() as Actor;
|
||||
@@ -639,6 +641,18 @@ namespace FlaxEditor.SceneGraph.GUI
|
||||
ActorNode.Root.Spawn(actor, spawnParent);
|
||||
actor.OrderInParent = newOrder;
|
||||
}
|
||||
else if (scriptType != ScriptType.Null)
|
||||
{
|
||||
if (DragOverMode == DragItemPositioning.Above || DragOverMode == DragItemPositioning.Below)
|
||||
{
|
||||
Editor.LogWarning("Failed to spawn script of type " + actorType.TypeName);
|
||||
continue;
|
||||
}
|
||||
IUndoAction action = new AddRemoveScript(true, newParent, scriptType);
|
||||
Select();
|
||||
ActorNode.Root.Undo?.AddAction(action);
|
||||
action.Do();
|
||||
}
|
||||
}
|
||||
result = DragDropEffect.Move;
|
||||
}
|
||||
@@ -699,9 +713,9 @@ namespace FlaxEditor.SceneGraph.GUI
|
||||
return Editor.Instance.CodeEditing.Controls.Get().Contains(controlType);
|
||||
}
|
||||
|
||||
private static bool ValidateDragScriptItem(ScriptItem script)
|
||||
private bool ValidateDragScriptItem(ScriptItem script)
|
||||
{
|
||||
return Editor.Instance.CodeEditing.Actors.Get(script) != ScriptType.Null;
|
||||
return Editor.Instance.CodeEditing.Actors.Get(script) != ScriptType.Null || Editor.Instance.CodeEditing.Scripts.Get(script) != ScriptType.Null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -51,12 +51,12 @@ namespace FlaxEditor.Scripting
|
||||
int standardToken = _managed?.MetadataToken ?? _custom?.MetadataToken ?? 0;
|
||||
if (_managed is PropertyInfo && _managed.DeclaringType != null)
|
||||
{
|
||||
var field = _managed.DeclaringType.GetField(string.Format("<{0}>k__BackingField", Name), BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
if (field == null || field.MetadataToken == 0)
|
||||
var backingField = _managed.DeclaringType.GetField(string.Format("<{0}>k__BackingField", Name), BindingFlags.Instance | BindingFlags.NonPublic);
|
||||
if (backingField == null || backingField.MetadataToken == 0)
|
||||
{
|
||||
return standardToken;
|
||||
}
|
||||
return field.MetadataToken;
|
||||
return backingField.MetadataToken;
|
||||
}
|
||||
return standardToken;
|
||||
}
|
||||
|
||||
@@ -71,7 +71,6 @@ namespace FlaxEditor.States
|
||||
{
|
||||
// Skip compilation on startup
|
||||
OnCompilationEnd(true);
|
||||
Editor.EndInit();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,6 @@ namespace FlaxEditor.States
|
||||
{
|
||||
if (!IsActive)
|
||||
throw new InvalidOperationException();
|
||||
|
||||
Time.GamePaused = value;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Op1(1, "Boolean NOT", "Negates the boolean value", new[] { "!", "~" }),
|
||||
Op2(2, "Boolean AND", "Performs a logical conjunction on two values", new[] { "&&" }),
|
||||
Op2(3, "Boolean OR", "Returns true if either (or both) of its operands is true", new[] { "||" }),
|
||||
Op2(4, "Boolean XOR", "", new [] { "^" } ),
|
||||
Op2(4, "Boolean XOR", "", new[] { "^" }),
|
||||
Op2(5, "Boolean NOR", ""),
|
||||
Op2(6, "Boolean NAND", ""),
|
||||
};
|
||||
|
||||
@@ -47,7 +47,8 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
base.OnShowSecondaryContextMenu(menu, location);
|
||||
|
||||
menu.AddSeparator();
|
||||
menu.AddButton("Convert to Parameter", OnConvertToParameter);
|
||||
var b = menu.AddButton("Convert to Parameter", OnConvertToParameter);
|
||||
b.Enabled = Surface.Owner is IVisjectSurfaceWindow window && Surface.Owner.SurfaceAsset && window.NewParameterTypes.Contains(_type);
|
||||
}
|
||||
|
||||
private void OnConvertToParameter()
|
||||
@@ -122,8 +123,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
|
||||
private bool OnParameterRenameValidate(string value)
|
||||
{
|
||||
if (Surface.Owner is not IVisjectSurfaceWindow window)
|
||||
throw new Exception("Surface owner is not a Visject Surface Window");
|
||||
var window = (IVisjectSurfaceWindow)Surface.Owner;
|
||||
return !string.IsNullOrWhiteSpace(value) && window.VisjectSurface.Parameters.All(x => x.Name != value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2198,21 +2198,23 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
_combobox.ClearItems();
|
||||
_tooltips.Clear();
|
||||
_functionNodesIds.Clear();
|
||||
var nodes = Surface.Nodes;
|
||||
var count = _signature != null ? nodes.Count : 0;
|
||||
for (int i = 0; i < count; i++)
|
||||
if (Surface != null && _signature != null)
|
||||
{
|
||||
if (nodes[i] is VisualScriptFunctionNode functionNode)
|
||||
var nodes = Surface.Nodes;
|
||||
for (int i = 0; i < nodes.Count; i++)
|
||||
{
|
||||
// Get if function signature matches the event signature
|
||||
functionNode.GetSignature(out var functionSig);
|
||||
if (IsValidFunctionSignature(ref functionSig))
|
||||
if (nodes[i] is VisualScriptFunctionNode functionNode)
|
||||
{
|
||||
if (functionNode.ID == handlerFunctionNodeId)
|
||||
toSelect = _functionNodesIds.Count;
|
||||
_functionNodesIds.Add(functionNode.ID);
|
||||
_tooltips.Add(functionNode.TooltipText);
|
||||
_combobox.AddItem(functionSig.ToString());
|
||||
// Get if function signature matches the event signature
|
||||
functionNode.GetSignature(out var functionSig);
|
||||
if (IsValidFunctionSignature(ref functionSig))
|
||||
{
|
||||
if (functionNode.ID == handlerFunctionNodeId)
|
||||
toSelect = _functionNodesIds.Count;
|
||||
_functionNodesIds.Add(functionNode.ID);
|
||||
_tooltips.Add(functionNode.TooltipText);
|
||||
_combobox.AddItem(functionSig.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,20 +71,20 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
// Layered material
|
||||
if (GetBox(MaterialNodeBoxes.Layer).HasAnyConnection)
|
||||
{
|
||||
GetBox(MaterialNodeBoxes.Color).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Mask).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Emissive).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Metalness).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Specular).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Roughness).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.AmbientOcclusion).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Normal).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Opacity).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Refraction).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.PositionOffset).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.TessellationMultiplier).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.WorldDisplacement).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.SubsurfaceColor).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Color).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.Mask).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.Emissive).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.Metalness).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.Specular).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.Roughness).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.AmbientOcclusion).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.Normal).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.Opacity).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.Refraction).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.PositionOffset).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.TessellationMultiplier).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.WorldDisplacement).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.SubsurfaceColor).IsActive = false;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -102,94 +102,94 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
bool isNotUnlit = info.ShadingModel != MaterialShadingModel.Unlit;
|
||||
bool withTess = info.TessellationMode != TessellationMethod.None;
|
||||
|
||||
GetBox(MaterialNodeBoxes.Color).Enabled = isNotUnlit;
|
||||
GetBox(MaterialNodeBoxes.Mask).Enabled = true;
|
||||
GetBox(MaterialNodeBoxes.Emissive).Enabled = true;
|
||||
GetBox(MaterialNodeBoxes.Metalness).Enabled = isNotUnlit;
|
||||
GetBox(MaterialNodeBoxes.Specular).Enabled = isNotUnlit;
|
||||
GetBox(MaterialNodeBoxes.Roughness).Enabled = isNotUnlit;
|
||||
GetBox(MaterialNodeBoxes.AmbientOcclusion).Enabled = isNotUnlit;
|
||||
GetBox(MaterialNodeBoxes.Normal).Enabled = isNotUnlit;
|
||||
GetBox(MaterialNodeBoxes.Opacity).Enabled = info.ShadingModel == MaterialShadingModel.Subsurface || info.ShadingModel == MaterialShadingModel.Foliage || info.BlendMode != MaterialBlendMode.Opaque;
|
||||
GetBox(MaterialNodeBoxes.Refraction).Enabled = info.BlendMode != MaterialBlendMode.Opaque;
|
||||
GetBox(MaterialNodeBoxes.PositionOffset).Enabled = true;
|
||||
GetBox(MaterialNodeBoxes.TessellationMultiplier).Enabled = withTess;
|
||||
GetBox(MaterialNodeBoxes.WorldDisplacement).Enabled = withTess;
|
||||
GetBox(MaterialNodeBoxes.SubsurfaceColor).Enabled = info.ShadingModel == MaterialShadingModel.Subsurface || info.ShadingModel == MaterialShadingModel.Foliage;
|
||||
GetBox(MaterialNodeBoxes.Color).IsActive = isNotUnlit;
|
||||
GetBox(MaterialNodeBoxes.Mask).IsActive = true;
|
||||
GetBox(MaterialNodeBoxes.Emissive).IsActive = true;
|
||||
GetBox(MaterialNodeBoxes.Metalness).IsActive = isNotUnlit;
|
||||
GetBox(MaterialNodeBoxes.Specular).IsActive = isNotUnlit;
|
||||
GetBox(MaterialNodeBoxes.Roughness).IsActive = isNotUnlit;
|
||||
GetBox(MaterialNodeBoxes.AmbientOcclusion).IsActive = isNotUnlit;
|
||||
GetBox(MaterialNodeBoxes.Normal).IsActive = isNotUnlit;
|
||||
GetBox(MaterialNodeBoxes.Opacity).IsActive = info.ShadingModel == MaterialShadingModel.Subsurface || info.ShadingModel == MaterialShadingModel.Foliage || info.BlendMode != MaterialBlendMode.Opaque;
|
||||
GetBox(MaterialNodeBoxes.Refraction).IsActive = info.BlendMode != MaterialBlendMode.Opaque;
|
||||
GetBox(MaterialNodeBoxes.PositionOffset).IsActive = true;
|
||||
GetBox(MaterialNodeBoxes.TessellationMultiplier).IsActive = withTess;
|
||||
GetBox(MaterialNodeBoxes.WorldDisplacement).IsActive = withTess;
|
||||
GetBox(MaterialNodeBoxes.SubsurfaceColor).IsActive = info.ShadingModel == MaterialShadingModel.Subsurface || info.ShadingModel == MaterialShadingModel.Foliage;
|
||||
break;
|
||||
}
|
||||
case MaterialDomain.PostProcess:
|
||||
{
|
||||
GetBox(MaterialNodeBoxes.Color).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Mask).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Emissive).Enabled = true;
|
||||
GetBox(MaterialNodeBoxes.Metalness).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Specular).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Roughness).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.AmbientOcclusion).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Normal).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Opacity).Enabled = true;
|
||||
GetBox(MaterialNodeBoxes.Refraction).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.PositionOffset).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.TessellationMultiplier).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.WorldDisplacement).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.SubsurfaceColor).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Color).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.Mask).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.Emissive).IsActive = true;
|
||||
GetBox(MaterialNodeBoxes.Metalness).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.Specular).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.Roughness).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.AmbientOcclusion).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.Normal).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.Opacity).IsActive = true;
|
||||
GetBox(MaterialNodeBoxes.Refraction).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.PositionOffset).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.TessellationMultiplier).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.WorldDisplacement).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.SubsurfaceColor).IsActive = false;
|
||||
break;
|
||||
}
|
||||
case MaterialDomain.Decal:
|
||||
{
|
||||
var mode = info.DecalBlendingMode;
|
||||
|
||||
GetBox(MaterialNodeBoxes.Color).Enabled = mode == MaterialDecalBlendingMode.Translucent || mode == MaterialDecalBlendingMode.Stain;
|
||||
GetBox(MaterialNodeBoxes.Mask).Enabled = true;
|
||||
GetBox(MaterialNodeBoxes.Emissive).Enabled = mode == MaterialDecalBlendingMode.Translucent || mode == MaterialDecalBlendingMode.Emissive;
|
||||
GetBox(MaterialNodeBoxes.Metalness).Enabled = mode == MaterialDecalBlendingMode.Translucent;
|
||||
GetBox(MaterialNodeBoxes.Specular).Enabled = mode == MaterialDecalBlendingMode.Translucent;
|
||||
GetBox(MaterialNodeBoxes.Roughness).Enabled = mode == MaterialDecalBlendingMode.Translucent;
|
||||
GetBox(MaterialNodeBoxes.AmbientOcclusion).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Normal).Enabled = mode == MaterialDecalBlendingMode.Translucent || mode == MaterialDecalBlendingMode.Normal;
|
||||
GetBox(MaterialNodeBoxes.Opacity).Enabled = true;
|
||||
GetBox(MaterialNodeBoxes.Refraction).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.PositionOffset).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.TessellationMultiplier).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.WorldDisplacement).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.SubsurfaceColor).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Color).IsActive = mode == MaterialDecalBlendingMode.Translucent || mode == MaterialDecalBlendingMode.Stain;
|
||||
GetBox(MaterialNodeBoxes.Mask).IsActive = true;
|
||||
GetBox(MaterialNodeBoxes.Emissive).IsActive = mode == MaterialDecalBlendingMode.Translucent || mode == MaterialDecalBlendingMode.Emissive;
|
||||
GetBox(MaterialNodeBoxes.Metalness).IsActive = mode == MaterialDecalBlendingMode.Translucent;
|
||||
GetBox(MaterialNodeBoxes.Specular).IsActive = mode == MaterialDecalBlendingMode.Translucent;
|
||||
GetBox(MaterialNodeBoxes.Roughness).IsActive = mode == MaterialDecalBlendingMode.Translucent;
|
||||
GetBox(MaterialNodeBoxes.AmbientOcclusion).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.Normal).IsActive = mode == MaterialDecalBlendingMode.Translucent || mode == MaterialDecalBlendingMode.Normal;
|
||||
GetBox(MaterialNodeBoxes.Opacity).IsActive = true;
|
||||
GetBox(MaterialNodeBoxes.Refraction).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.PositionOffset).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.TessellationMultiplier).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.WorldDisplacement).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.SubsurfaceColor).IsActive = false;
|
||||
break;
|
||||
}
|
||||
case MaterialDomain.GUI:
|
||||
{
|
||||
GetBox(MaterialNodeBoxes.Color).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Mask).Enabled = true;
|
||||
GetBox(MaterialNodeBoxes.Emissive).Enabled = true;
|
||||
GetBox(MaterialNodeBoxes.Metalness).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Specular).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Roughness).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.AmbientOcclusion).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Normal).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Opacity).Enabled = true;
|
||||
GetBox(MaterialNodeBoxes.Refraction).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.PositionOffset).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.TessellationMultiplier).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.WorldDisplacement).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.SubsurfaceColor).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Color).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.Mask).IsActive = true;
|
||||
GetBox(MaterialNodeBoxes.Emissive).IsActive = true;
|
||||
GetBox(MaterialNodeBoxes.Metalness).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.Specular).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.Roughness).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.AmbientOcclusion).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.Normal).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.Opacity).IsActive = true;
|
||||
GetBox(MaterialNodeBoxes.Refraction).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.PositionOffset).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.TessellationMultiplier).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.WorldDisplacement).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.SubsurfaceColor).IsActive = false;
|
||||
break;
|
||||
}
|
||||
case MaterialDomain.VolumeParticle:
|
||||
{
|
||||
GetBox(MaterialNodeBoxes.Color).Enabled = true;
|
||||
GetBox(MaterialNodeBoxes.Mask).Enabled = true;
|
||||
GetBox(MaterialNodeBoxes.Emissive).Enabled = true;
|
||||
GetBox(MaterialNodeBoxes.Metalness).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Specular).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Roughness).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.AmbientOcclusion).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Normal).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Opacity).Enabled = true;
|
||||
GetBox(MaterialNodeBoxes.Refraction).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.PositionOffset).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.TessellationMultiplier).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.WorldDisplacement).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.SubsurfaceColor).Enabled = false;
|
||||
GetBox(MaterialNodeBoxes.Color).IsActive = true;
|
||||
GetBox(MaterialNodeBoxes.Mask).IsActive = true;
|
||||
GetBox(MaterialNodeBoxes.Emissive).IsActive = true;
|
||||
GetBox(MaterialNodeBoxes.Metalness).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.Specular).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.Roughness).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.AmbientOcclusion).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.Normal).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.Opacity).IsActive = true;
|
||||
GetBox(MaterialNodeBoxes.Refraction).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.PositionOffset).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.TessellationMultiplier).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.WorldDisplacement).IsActive = false;
|
||||
GetBox(MaterialNodeBoxes.SubsurfaceColor).IsActive = false;
|
||||
break;
|
||||
}
|
||||
default: throw new ArgumentOutOfRangeException();
|
||||
@@ -936,6 +936,142 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(float), 2),
|
||||
}
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 43,
|
||||
Title = "Rotate UV",
|
||||
Description = "Rotates 2D vector by given angle around (0,0) origin",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(250, 40),
|
||||
ConnectionsHints = ConnectionsHint.Vector,
|
||||
DefaultValues =
|
||||
[
|
||||
0.0f,
|
||||
],
|
||||
Elements =
|
||||
[
|
||||
NodeElementArchetype.Factory.Input(0, "UV", true, typeof(Float2), 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Angle", true, typeof(float), 1, 0),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(Float2), 2),
|
||||
]
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 44,
|
||||
Title = "Cone Gradient",
|
||||
Description = "Creates cone gradient around normalized UVs (range [-1; 1]), angle is in radians (range [0; TwoPi])",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(175, 40),
|
||||
ConnectionsHints = ConnectionsHint.Vector,
|
||||
DefaultValues =
|
||||
[
|
||||
0.0f,
|
||||
],
|
||||
Elements =
|
||||
[
|
||||
NodeElementArchetype.Factory.Input(0, "UV", true, typeof(Float2), 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Angle", true, typeof(float), 1, 0),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(float), 2),
|
||||
]
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 45,
|
||||
Title = "Cycle Gradient",
|
||||
Description = "Creates 2D sphere mask gradient around normalized UVs (range [-1; 1])",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(175, 20),
|
||||
ConnectionsHints = ConnectionsHint.Vector,
|
||||
Elements =
|
||||
[
|
||||
NodeElementArchetype.Factory.Input(0, "UV", true, typeof(Float2), 0),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(float), 1),
|
||||
]
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 46,
|
||||
Title = "Falloff and Offset",
|
||||
Description = "",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(175, 60),
|
||||
ConnectionsHints = ConnectionsHint.Numeric,
|
||||
DefaultValues =
|
||||
[
|
||||
0.0f,
|
||||
0.9f
|
||||
],
|
||||
Elements =
|
||||
[
|
||||
NodeElementArchetype.Factory.Input(0, "Value", true, typeof(float), 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Offset", true, typeof(float), 1, 0),
|
||||
NodeElementArchetype.Factory.Input(2, "Falloff", true, typeof(float), 2, 1),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(float), 3),
|
||||
]
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 47,
|
||||
Title = "Linear Gradient",
|
||||
Description = "x = Gradient along X axis, y = Gradient along Y axis",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(175, 60),
|
||||
ConnectionsHints = ConnectionsHint.Vector,
|
||||
DefaultValues =
|
||||
[
|
||||
0.0f,
|
||||
false
|
||||
],
|
||||
Elements =
|
||||
[
|
||||
NodeElementArchetype.Factory.Input(0, "UV", true, typeof(Float2), 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Angle", true, typeof(float), 1, 0),
|
||||
NodeElementArchetype.Factory.Input(2, "Mirror", true, typeof(bool), 2, 1),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(Float2), 3),
|
||||
]
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 48,
|
||||
Title = "Radial Gradient",
|
||||
Description = "",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(175, 40),
|
||||
ConnectionsHints = ConnectionsHint.Vector,
|
||||
DefaultValues =
|
||||
[
|
||||
0.0f,
|
||||
],
|
||||
Elements =
|
||||
[
|
||||
NodeElementArchetype.Factory.Input(0, "UV", true, typeof(Float2), 0),
|
||||
NodeElementArchetype.Factory.Input(1, "Angle", true, typeof(float), 1, 0),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(float), 2),
|
||||
]
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 49,
|
||||
Title = "Ring Gradient",
|
||||
Description = "x = InnerMask,y = OuterMask,z = Mask",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(175, 80),
|
||||
ConnectionsHints = ConnectionsHint.Vector,
|
||||
DefaultValues =
|
||||
[
|
||||
1.0f,
|
||||
0.8f,
|
||||
0.05f,
|
||||
],
|
||||
Elements =
|
||||
[
|
||||
NodeElementArchetype.Factory.Input(0, "UV", true, typeof(Float2), 0),
|
||||
NodeElementArchetype.Factory.Input(1, "OuterBounds", true, typeof(float), 1, 0),
|
||||
NodeElementArchetype.Factory.Input(2, "InnerBounds", true, typeof(float), 2, 1),
|
||||
NodeElementArchetype.Factory.Input(3, "Falloff", true, typeof(float), 3, 2),
|
||||
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(Float3), 4),
|
||||
]
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,10 +114,10 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Op1(13, "Round", "Rounds A to the nearest integer"),
|
||||
Op1(14, "Saturate", "Clamps A to the range [0, 1]"),
|
||||
Op1(15, "Sine", "Returns sine of A"),
|
||||
Op1(16, "Sqrt", "Returns square root of A", new [] { "Square Root", "Square", "Root" }),
|
||||
Op1(16, "Sqrt", "Returns square root of A", new[] { "Square Root", "Square", "Root" }),
|
||||
Op1(17, "Tangent", "Returns tangent of A"),
|
||||
Op2(18, "Cross", "Returns the cross product of A and B", ConnectionsHint.None, typeof(Float3)),
|
||||
Op2(19, "Distance", "Returns a distance scalar between A and B", new [] { "Magnitude", "Mag", "Length" }, ConnectionsHint.Vector, null, typeof(float), false),
|
||||
Op2(19, "Distance", "Returns a distance scalar between A and B", new[] { "Magnitude", "Mag", "Length" }, ConnectionsHint.Vector, null, typeof(float), false),
|
||||
Op2(20, "Dot", "Returns the dot product of A and B", ConnectionsHint.Vector, null, typeof(float), false),
|
||||
Op2(21, "Max", "Selects the greater of A and B"),
|
||||
Op2(22, "Min", "Selects the lesser of A and B"),
|
||||
@@ -192,7 +192,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
}
|
||||
},
|
||||
//
|
||||
Op1(27, "Negate", "Returns opposite value", new [] { "Invert" }),
|
||||
Op1(27, "Negate", "Returns opposite value", new[] { "Invert" }),
|
||||
Op1(28, "One Minus", "Returns 1 - value"),
|
||||
//
|
||||
new NodeArchetype
|
||||
@@ -232,7 +232,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 31,
|
||||
Title = "Mad",
|
||||
AlternativeTitles = new [] { "Multiply", "Add", "*+" },
|
||||
AlternativeTitles = new[] { "Multiply", "Add", "*+" },
|
||||
Description = "Performs value multiplication and addition at once",
|
||||
Flags = NodeFlags.AllGraphs,
|
||||
Size = new Float2(160, 60),
|
||||
@@ -430,7 +430,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
Title = "Smoothstep",
|
||||
Description = "Returns a smooth Hermite interpolation between 0 and 1, if value is in the range [min, max].",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(120, 60),
|
||||
Size = new Float2(200, 60),
|
||||
ConnectionsHints = ConnectionsHint.Numeric,
|
||||
IndependentBoxes = new[] { 0, 1, 2 },
|
||||
DependentBoxes = new[] { 3 },
|
||||
|
||||
@@ -399,7 +399,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
private void UpdateInputBox()
|
||||
{
|
||||
var facingMode = (ParticleSpriteFacingMode)Values[2];
|
||||
GetBox(0).Enabled = facingMode == ParticleSpriteFacingMode.CustomFacingVector || facingMode == ParticleSpriteFacingMode.FixedAxis;
|
||||
GetBox(0).IsActive = facingMode == ParticleSpriteFacingMode.CustomFacingVector || facingMode == ParticleSpriteFacingMode.FixedAxis;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -434,6 +434,19 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
NodeElementArchetype.Factory.ComboBox(50, Surface.Constants.LayoutOffsetY * 4, 100, 0, typeof(CommonSamplerType))
|
||||
}
|
||||
},
|
||||
new NodeArchetype
|
||||
{
|
||||
TypeID = 18,
|
||||
Title = "Lightmap UV",
|
||||
AlternativeTitles = new string[] { "Lightmap TexCoord" },
|
||||
Description = "Lightmap UVs",
|
||||
Flags = NodeFlags.MaterialGraph,
|
||||
Size = new Float2(110, 30),
|
||||
Elements = new []
|
||||
{
|
||||
NodeElementArchetype.Factory.Output(0, "UVs", typeof(Float2), 0)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1032,7 +1032,8 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
private Rectangle _localBounds;
|
||||
private InputBox _input;
|
||||
private OutputBox _output;
|
||||
private bool _isMouseDown, _isConnecting;
|
||||
private bool _isMouseDown, _isConnecting, _isMouseInConnectingBounds;
|
||||
private const float ConnectingBounds = -12.0f;
|
||||
|
||||
/// <inheritdoc />
|
||||
public RerouteNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch)
|
||||
@@ -1170,7 +1171,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
if (button == MouseButton.Left)
|
||||
{
|
||||
_isMouseDown = true;
|
||||
_isConnecting = _localBounds.MakeExpanded(-10.0f).Contains(ref location); // Inner area for connecting, outer area for moving
|
||||
_isConnecting = _isMouseInConnectingBounds;
|
||||
if (_isConnecting)
|
||||
{
|
||||
Focus();
|
||||
@@ -1189,12 +1190,22 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
if (Surface.CanEdit && _isConnecting)
|
||||
Surface.ConnectingStart(this);
|
||||
}
|
||||
|
||||
_isMouseInConnectingBounds = false;
|
||||
Cursor = CursorType.Default;
|
||||
|
||||
base.OnMouseLeave();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnMouseMove(Float2 location)
|
||||
{
|
||||
_isMouseInConnectingBounds = IsMouseOver && _localBounds.MakeExpanded(ConnectingBounds).Contains(ref location); // Inner area for connecting, outer area for moving
|
||||
if (!_isMouseInConnectingBounds && !_isMouseDown)
|
||||
Cursor = CursorType.SizeAll;
|
||||
else
|
||||
Cursor = CursorType.Default;
|
||||
|
||||
Surface.ConnectingOver(this);
|
||||
base.OnMouseMove(location);
|
||||
}
|
||||
@@ -1255,7 +1266,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
/// <inheritdoc />
|
||||
public void DrawConnectingLine(ref Float2 startPos, ref Float2 endPos, ref Color color)
|
||||
{
|
||||
OutputBox.DrawConnection(Surface.Style, ref startPos, ref endPos, ref color, 2);
|
||||
OutputBox.DrawConnection(Surface.Style, ref startPos, ref endPos, ref color, OutputBox.ConnectingConnectionThickness);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -1483,7 +1494,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 11,
|
||||
Title = "Comment",
|
||||
AlternativeTitles = new[] { "//" , "Group" },
|
||||
AlternativeTitles = new[] { "//", "Group" },
|
||||
TryParseText = (string filterText, out object[] data) =>
|
||||
{
|
||||
data = null;
|
||||
@@ -1639,7 +1650,7 @@ namespace FlaxEditor.Surface.Archetypes
|
||||
{
|
||||
TypeID = 22,
|
||||
Title = "As",
|
||||
AlternativeTitles = new [] { "Cast" },
|
||||
AlternativeTitles = new[] { "Cast" },
|
||||
Create = (id, context, arch, groupArch) => new AsNode(id, context, arch, groupArch),
|
||||
Description = "Casts the object to a different type. Returns null if cast fails.",
|
||||
Flags = NodeFlags.VisualScriptGraph | NodeFlags.AnimGraph,
|
||||
|
||||
@@ -307,7 +307,10 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
if (!IsLayoutLocked)
|
||||
{
|
||||
group.UnlockChildrenRecursive();
|
||||
SortGroups();
|
||||
if (_contextSensitiveSearchEnabled && _selectedBox != null)
|
||||
UpdateFilters();
|
||||
else
|
||||
SortGroups();
|
||||
if (ShowExpanded)
|
||||
group.Open(false);
|
||||
group.PerformLayout();
|
||||
@@ -367,7 +370,10 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
|
||||
if (!isLayoutLocked)
|
||||
{
|
||||
SortGroups();
|
||||
if (_contextSensitiveSearchEnabled && _selectedBox != null)
|
||||
UpdateFilters();
|
||||
else
|
||||
SortGroups();
|
||||
Profiler.BeginEvent("Perform Layout");
|
||||
UnlockChildrenRecursive();
|
||||
foreach (var group in groups)
|
||||
@@ -482,10 +488,11 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
|
||||
// Update groups
|
||||
LockChildrenRecursive();
|
||||
var contextSensitiveSelectedBox = _contextSensitiveSearchEnabled ? _selectedBox : null;
|
||||
for (int i = 0; i < _groups.Count; i++)
|
||||
{
|
||||
_groups[i].UpdateFilter(_searchBox.Text, _contextSensitiveSearchEnabled ? _selectedBox : null);
|
||||
_groups[i].UpdateItemSort(_selectedBox);
|
||||
_groups[i].UpdateFilter(_searchBox.Text, contextSensitiveSelectedBox);
|
||||
_groups[i].UpdateItemSort(contextSensitiveSelectedBox);
|
||||
}
|
||||
SortGroups();
|
||||
UnlockChildrenRecursive();
|
||||
@@ -560,7 +567,10 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
}
|
||||
UnlockChildrenRecursive();
|
||||
|
||||
SortGroups();
|
||||
if (_contextSensitiveSearchEnabled && _selectedBox != null)
|
||||
UpdateFilters();
|
||||
else
|
||||
SortGroups();
|
||||
PerformLayout();
|
||||
|
||||
Profiler.EndEvent();
|
||||
|
||||
@@ -89,6 +89,30 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
{
|
||||
Profiler.BeginEvent("VisjectCMGroup.UpdateFilter");
|
||||
|
||||
// Check if a dot is inside the filter text and split the string accordingly.
|
||||
// Everything in front of the dot is for specifying a class/group name. And everything afterward is the actual item filter text
|
||||
if (!string.IsNullOrEmpty(filterText))
|
||||
{
|
||||
int dotIndex = filterText.IndexOf('.');
|
||||
if (dotIndex != -1)
|
||||
{
|
||||
string filterGroupName = filterText.Substring(0, dotIndex);
|
||||
|
||||
// If the string in front of the dot has the length of 0 or doesn't start with a letter we skip the filtering to make spawning floats work
|
||||
if (filterGroupName.Length > 0 && char.IsLetter(filterGroupName[0]))
|
||||
{
|
||||
// Early out and make the group invisible if it doesn't start with the specified string
|
||||
if (!Name.StartsWith(filterGroupName, StringComparison.InvariantCultureIgnoreCase))
|
||||
{
|
||||
Visible = false;
|
||||
Profiler.EndEvent();
|
||||
return;
|
||||
}
|
||||
filterText = filterText.Substring(dotIndex + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update items
|
||||
bool isAnyVisible = false;
|
||||
bool groupHeaderMatches = QueryFilterHelper.Match(filterText, HeaderText);
|
||||
@@ -177,6 +201,13 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
SortScore = item.SortScore;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectedBox != null)
|
||||
{
|
||||
if (string.Equals(Name, selectedBox.CurrentType.Name, StringComparison.InvariantCultureIgnoreCase))
|
||||
SortScore += 10;
|
||||
}
|
||||
|
||||
SortChildren();
|
||||
|
||||
Profiler.EndEvent();
|
||||
|
||||
@@ -219,7 +219,7 @@ namespace FlaxEditor.Surface.ContextMenu
|
||||
}
|
||||
|
||||
// Check archetype synonyms
|
||||
if (_archetype.AlternativeTitles!= null && _archetype.AlternativeTitles.Any(altTitle => QueryFilterHelper.Match(filterText, altTitle, out ranges)))
|
||||
if (_archetype.AlternativeTitles != null && _archetype.AlternativeTitles.Any(altTitle => QueryFilterHelper.Match(filterText, altTitle, out ranges)))
|
||||
{
|
||||
// Update highlights
|
||||
if (_highlights == null)
|
||||
|
||||
@@ -41,6 +41,11 @@ namespace FlaxEditor.Surface.Elements
|
||||
/// </summary>
|
||||
protected bool _isSelected;
|
||||
|
||||
/// <summary>
|
||||
/// The is active flag for the box. Unlike <see cref="FlaxEngine.GUI.Control.Enabled"/>, inactive boxes can still be interacted with, they just will be drawn like disabled boxes
|
||||
/// </summary>
|
||||
protected bool _isActive = true;
|
||||
|
||||
/// <summary>
|
||||
/// Unique box ID within single node.
|
||||
/// </summary>
|
||||
@@ -180,6 +185,15 @@ namespace FlaxEditor.Surface.Elements
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the active state of the box. Unlike <see cref="FlaxEngine.GUI.Control.Enabled"/>, inactive boxes can still be interacted with, they just will be drawn like disabled boxes
|
||||
/// </summary>
|
||||
public bool IsActive
|
||||
{
|
||||
get => _isActive;
|
||||
set => _isActive = value;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected Box(SurfaceNode parentNode, NodeElementArchetype archetype, Float2 location)
|
||||
: base(parentNode, archetype, location, new Float2(Constants.BoxSize), false)
|
||||
@@ -724,7 +738,7 @@ namespace FlaxEditor.Surface.Elements
|
||||
/// <inheritdoc />
|
||||
public void DrawConnectingLine(ref Float2 startPos, ref Float2 endPos, ref Color color)
|
||||
{
|
||||
OutputBox.DrawConnection(Surface.Style, ref startPos, ref endPos, ref color, 2);
|
||||
OutputBox.DrawConnection(Surface.Style, ref startPos, ref endPos, ref color, OutputBox.ConnectingConnectionThickness);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace FlaxEditor.Surface.Elements
|
||||
ParentNode.ValuesChanged += OnNodeValuesChanged;
|
||||
|
||||
// Disable slider if surface doesn't allow it
|
||||
if (!ParentNode.Surface.CanLivePreviewValueChanges)
|
||||
if (ParentNode.Surface != null && !ParentNode.Surface.CanLivePreviewValueChanges)
|
||||
_slideSpeed = 0.0f;
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
using FlaxEngine;
|
||||
using FlaxEngine.GUI;
|
||||
using System;
|
||||
using FlaxEditor.Options;
|
||||
|
||||
namespace FlaxEditor.Surface.Elements
|
||||
{
|
||||
@@ -13,6 +14,26 @@ namespace FlaxEditor.Surface.Elements
|
||||
[HideInEditor]
|
||||
public class OutputBox : Box
|
||||
{
|
||||
/// <summary>
|
||||
/// The default thickness of the connection line
|
||||
/// </summary>
|
||||
public const float DefaultConnectionThickness = 1.5f;
|
||||
|
||||
/// <summary>
|
||||
/// The thickness of a highlighted connection line
|
||||
/// </summary>
|
||||
public const float ConnectingConnectionThickness = 2.5f;
|
||||
|
||||
/// <summary>
|
||||
/// The thickness of the selected connection line
|
||||
/// </summary>
|
||||
public const float SelectedConnectionThickness = 3f;
|
||||
|
||||
/// <summary>
|
||||
/// The offset between the connection line and the box
|
||||
/// </summary>
|
||||
public const float DefaultConnectionOffset = 24f;
|
||||
|
||||
/// <summary>
|
||||
/// Distance for the mouse to be considered above the connection
|
||||
/// </summary>
|
||||
@@ -32,7 +53,7 @@ namespace FlaxEditor.Surface.Elements
|
||||
/// <param name="end">The end location.</param>
|
||||
/// <param name="color">The connection color.</param>
|
||||
/// <param name="thickness">The connection thickness.</param>
|
||||
public static void DrawConnection(SurfaceStyle style, ref Float2 start, ref Float2 end, ref Color color, float thickness = 1)
|
||||
public static void DrawConnection(SurfaceStyle style, ref Float2 start, ref Float2 end, ref Color color, float thickness = DefaultConnectionThickness)
|
||||
{
|
||||
if (style.DrawConnection != null)
|
||||
{
|
||||
@@ -40,11 +61,22 @@ namespace FlaxEditor.Surface.Elements
|
||||
return;
|
||||
}
|
||||
|
||||
float connectionOffset = Mathf.Max(0f, DefaultConnectionOffset * (1 - Editor.Instance.Options.Options.Interface.ConnectionCurvature));
|
||||
Float2 offsetStart = new Float2(start.X + connectionOffset, start.Y);
|
||||
Float2 offsetEnd = new Float2(end.X - connectionOffset, end.Y);
|
||||
|
||||
// Calculate control points
|
||||
CalculateBezierControlPoints(start, end, out var control1, out var control2);
|
||||
CalculateBezierControlPoints(offsetStart, offsetEnd, out var control1, out var control2);
|
||||
|
||||
// Draw offset lines only if necessary
|
||||
if (connectionOffset >= float.Epsilon)
|
||||
{
|
||||
Render2D.DrawLine(start, offsetStart, color, thickness);
|
||||
Render2D.DrawLine(offsetEnd, end, color, thickness);
|
||||
}
|
||||
|
||||
// Draw line
|
||||
Render2D.DrawBezier(start, control1, control2, end, color, thickness);
|
||||
Render2D.DrawBezier(offsetStart, control1, control2, offsetEnd, color, thickness);
|
||||
|
||||
/*
|
||||
// Debug drawing control points
|
||||
@@ -57,8 +89,8 @@ namespace FlaxEditor.Surface.Elements
|
||||
private static void CalculateBezierControlPoints(Float2 start, Float2 end, out Float2 control1, out Float2 control2)
|
||||
{
|
||||
// Control points parameters
|
||||
const float minControlLength = 100f;
|
||||
const float maxControlLength = 150f;
|
||||
const float minControlLength = 50f;
|
||||
const float maxControlLength = 120f;
|
||||
var dst = (end - start).Length;
|
||||
var yDst = Mathf.Abs(start.Y - end.Y);
|
||||
|
||||
@@ -66,6 +98,7 @@ namespace FlaxEditor.Surface.Elements
|
||||
var minControlDst = dst * 0.5f;
|
||||
var maxControlDst = Mathf.Max(Mathf.Min(maxControlLength, dst), minControlLength);
|
||||
var controlDst = Mathf.Lerp(minControlDst, maxControlDst, Mathf.Clamp(yDst / minControlLength, 0f, 1f));
|
||||
controlDst *= Editor.Instance.Options.Options.Interface.ConnectionCurvature;
|
||||
|
||||
control1 = new Float2(start.X + controlDst, start.Y);
|
||||
control2 = new Float2(end.X - controlDst, end.Y);
|
||||
@@ -78,9 +111,10 @@ namespace FlaxEditor.Surface.Elements
|
||||
/// <param name="mousePosition">The mouse position</param>
|
||||
public bool IntersectsConnection(Box targetBox, ref Float2 mousePosition)
|
||||
{
|
||||
var startPos = ConnectionOrigin;
|
||||
var endPos = targetBox.ConnectionOrigin;
|
||||
return IntersectsConnection(ref startPos, ref endPos, ref mousePosition, MouseOverConnectionDistance);
|
||||
float connectionOffset = Mathf.Max(0f, DefaultConnectionOffset * (1 - Editor.Instance.Options.Options.Interface.ConnectionCurvature));
|
||||
Float2 start = new Float2(ConnectionOrigin.X + connectionOffset, ConnectionOrigin.Y);
|
||||
Float2 end = new Float2(targetBox.ConnectionOrigin.X - connectionOffset, targetBox.ConnectionOrigin.Y);
|
||||
return IntersectsConnection(ref start, ref end, ref mousePosition, MouseOverConnectionDistance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -100,22 +134,26 @@ namespace FlaxEditor.Surface.Elements
|
||||
if ((point.Y - (start.Y - offset)) * ((end.Y + offset) - point.Y) < 0)
|
||||
return false;
|
||||
|
||||
float squaredDistance = distance;
|
||||
CalculateBezierControlPoints(start, end, out var control1, out var control2);
|
||||
float connectionOffset = Mathf.Max(0f, DefaultConnectionOffset * (1 - Editor.Instance.Options.Options.Interface.ConnectionCurvature));
|
||||
Float2 offsetStart = new Float2(start.X + connectionOffset, start.Y);
|
||||
Float2 offsetEnd = new Float2(end.X - connectionOffset, end.Y);
|
||||
|
||||
var d1 = control1 - start;
|
||||
float squaredDistance = distance;
|
||||
CalculateBezierControlPoints(offsetStart, offsetEnd, out var control1, out var control2);
|
||||
|
||||
var d1 = control1 - offsetStart;
|
||||
var d2 = control2 - control1;
|
||||
var d3 = end - control2;
|
||||
var d3 = offsetEnd - control2;
|
||||
float len = d1.Length + d2.Length + d3.Length;
|
||||
int segmentCount = Math.Min(Math.Max(Mathf.CeilToInt(len * 0.05f), 1), 100);
|
||||
float segmentCountInv = 1.0f / segmentCount;
|
||||
|
||||
Bezier(ref start, ref control1, ref control2, ref end, 0, out var p);
|
||||
Bezier(ref offsetStart, ref control1, ref control2, ref offsetEnd, 0, out var p);
|
||||
for (int i = 1; i <= segmentCount; i++)
|
||||
{
|
||||
var oldp = p;
|
||||
float t = i * segmentCountInv;
|
||||
Bezier(ref start, ref control1, ref control2, ref end, t, out p);
|
||||
Bezier(ref offsetStart, ref control1, ref control2, ref offsetEnd, t, out p);
|
||||
|
||||
// Maybe it would be reasonable to return the point?
|
||||
CollisionsHelper.ClosestPointPointLine(ref point, ref oldp, ref p, out var result);
|
||||
@@ -151,15 +189,21 @@ namespace FlaxEditor.Surface.Elements
|
||||
{
|
||||
Box targetBox = Connections[i];
|
||||
var endPos = targetBox.ConnectionOrigin;
|
||||
var highlight = 1 + Mathf.Max(startHighlight, targetBox.ConnectionsHighlightIntensity);
|
||||
var color = _currentTypeColor * highlight;
|
||||
var highlight = DefaultConnectionThickness + Mathf.Max(startHighlight, targetBox.ConnectionsHighlightIntensity);
|
||||
var alpha = targetBox.Enabled && targetBox.IsActive ? 1.0f : 0.6f;
|
||||
|
||||
// We have to calculate an offset here to preserve the original color for when the default connection thickness is larger than 1
|
||||
var highlightOffset = (highlight - (DefaultConnectionThickness - 1));
|
||||
var color = _currentTypeColor * highlightOffset * alpha;
|
||||
|
||||
// TODO: Figure out how to only draw the topmost connection
|
||||
if (IntersectsConnection(ref startPos, ref endPos, ref mousePosition, mouseOverDistance))
|
||||
{
|
||||
highlight += 0.5f;
|
||||
}
|
||||
highlight += DefaultConnectionThickness * 0.5f;
|
||||
|
||||
// Increase thickness on impulse/ execution lines
|
||||
if (targetBox.CurrentType.IsVoid)
|
||||
highlight *= 2;
|
||||
|
||||
DrawConnection(style, ref startPos, ref endPos, ref color, highlight);
|
||||
}
|
||||
}
|
||||
@@ -172,7 +216,9 @@ namespace FlaxEditor.Surface.Elements
|
||||
// Draw all the connections
|
||||
var startPos = ConnectionOrigin;
|
||||
var endPos = targetBox.ConnectionOrigin;
|
||||
DrawConnection(Surface.Style, ref startPos, ref endPos, ref _currentTypeColor, 2.5f);
|
||||
var alpha = targetBox.Enabled && targetBox.IsActive ? 1.0f : 0.6f;
|
||||
var color = _currentTypeColor * alpha;
|
||||
DrawConnection(Surface.Style, ref startPos, ref endPos, ref color, SelectedConnectionThickness);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -20,12 +20,18 @@ namespace FlaxEditor.Surface
|
||||
private Rectangle _colorButtonRect;
|
||||
private Rectangle _resizeButtonRect;
|
||||
private Float2 _startResizingSize;
|
||||
private readonly TextBox _renameTextBox;
|
||||
|
||||
/// <summary>
|
||||
/// True if sizing tool is in use.
|
||||
/// </summary>
|
||||
protected bool _isResizing;
|
||||
|
||||
/// <summary>
|
||||
/// True if rename textbox is active in order to rename comment
|
||||
/// </summary>
|
||||
protected bool _isRenaming;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the color of the comment.
|
||||
/// </summary>
|
||||
@@ -63,6 +69,13 @@ namespace FlaxEditor.Surface
|
||||
public SurfaceComment(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch)
|
||||
: base(id, context, nodeArch, groupArch)
|
||||
{
|
||||
_renameTextBox = new TextBox(false, 0, 0, Width)
|
||||
{
|
||||
Height = Constants.NodeHeaderSize,
|
||||
Visible = false,
|
||||
Parent = this,
|
||||
EndEditOnClick = false, // We have to handle this ourselves, otherwise the textbox instantly loses focus when double-clicking the header
|
||||
};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -83,7 +96,7 @@ namespace FlaxEditor.Surface
|
||||
IndexInParent = 0;
|
||||
OrderValue = IndexInParent;
|
||||
}
|
||||
else if(OrderValue != -1)
|
||||
else if (OrderValue != -1)
|
||||
{
|
||||
IndexInParent = OrderValue;
|
||||
}
|
||||
@@ -97,7 +110,7 @@ namespace FlaxEditor.Surface
|
||||
// Randomize color
|
||||
Color = ColorValue = Color.FromHSV(new Random().NextFloat(0, 360), 0.7f, 0.25f, 0.8f);
|
||||
|
||||
if(OrderValue == -1)
|
||||
if (OrderValue == -1)
|
||||
OrderValue = Context.CommentCount - 1;
|
||||
IndexInParent = OrderValue;
|
||||
}
|
||||
@@ -149,6 +162,20 @@ namespace FlaxEditor.Surface
|
||||
_closeButtonRect = new Rectangle(Width - buttonSize - buttonMargin, buttonMargin, buttonSize, buttonSize);
|
||||
_colorButtonRect = new Rectangle(_closeButtonRect.Left - buttonSize - buttonMargin, buttonMargin, buttonSize, buttonSize);
|
||||
_resizeButtonRect = new Rectangle(_closeButtonRect.Left, Height - buttonSize - buttonMargin, buttonSize, buttonSize);
|
||||
_renameTextBox.Width = Width;
|
||||
_renameTextBox.Height = headerSize;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Update(float deltaTime)
|
||||
{
|
||||
if (_isRenaming && (!_renameTextBox.IsFocused || !RootWindow.IsFocused))
|
||||
{
|
||||
Rename(_renameTextBox.Text);
|
||||
StopRenaming();
|
||||
}
|
||||
|
||||
base.Update(deltaTime);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@@ -158,7 +185,7 @@ namespace FlaxEditor.Surface
|
||||
var color = Color;
|
||||
var backgroundRect = new Rectangle(Float2.Zero, Size);
|
||||
var headerColor = new Color(Mathf.Clamp(color.R, 0.1f, 0.3f), Mathf.Clamp(color.G, 0.1f, 0.3f), Mathf.Clamp(color.B, 0.1f, 0.3f), 0.4f);
|
||||
if (IsSelected)
|
||||
if (IsSelected && !_isRenaming)
|
||||
headerColor *= 2.0f;
|
||||
|
||||
// Paint background
|
||||
@@ -169,7 +196,8 @@ namespace FlaxEditor.Surface
|
||||
|
||||
// Header
|
||||
Render2D.FillRectangle(_headerRect, headerColor);
|
||||
Render2D.DrawText(style.FontLarge, Title, _headerRect, style.Foreground, TextAlignment.Center, TextAlignment.Center);
|
||||
if (!_isRenaming)
|
||||
Render2D.DrawText(style.FontLarge, Title, _headerRect, style.Foreground, TextAlignment.Center, TextAlignment.Center);
|
||||
|
||||
// Close button
|
||||
Render2D.DrawSprite(style.Cross, _closeButtonRect, _closeButtonRect.Contains(_mousePosition) && Surface.CanEdit ? style.Foreground : style.ForegroundGrey);
|
||||
@@ -213,6 +241,13 @@ namespace FlaxEditor.Surface
|
||||
EndResizing();
|
||||
}
|
||||
|
||||
// Check if was renaming
|
||||
if (_isRenaming)
|
||||
{
|
||||
Rename(_renameTextBox.Text);
|
||||
StopRenaming();
|
||||
}
|
||||
|
||||
// Base
|
||||
base.OnLostFocus();
|
||||
}
|
||||
@@ -294,17 +329,47 @@ namespace FlaxEditor.Surface
|
||||
/// </summary>
|
||||
public void StartRenaming()
|
||||
{
|
||||
Surface.Select(this);
|
||||
var dialog = RenamePopup.Show(this, _headerRect, Title, false);
|
||||
dialog.Renamed += OnRenamed;
|
||||
_isRenaming = true;
|
||||
_renameTextBox.Visible = true;
|
||||
_renameTextBox.SetText(Title);
|
||||
_renameTextBox.Focus();
|
||||
_renameTextBox.SelectAll();
|
||||
}
|
||||
|
||||
private void OnRenamed(RenamePopup renamePopup)
|
||||
private void StopRenaming()
|
||||
{
|
||||
Title = TitleValue = renamePopup.Text;
|
||||
_isRenaming = false;
|
||||
_renameTextBox.Visible = false;
|
||||
}
|
||||
|
||||
private void Rename(string newTitle)
|
||||
{
|
||||
if (string.Equals(Title, newTitle, StringComparison.Ordinal))
|
||||
return;
|
||||
|
||||
Title = TitleValue = newTitle;
|
||||
Surface.MarkAsEdited(false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnKeyDown(KeyboardKeys key)
|
||||
{
|
||||
if (key == KeyboardKeys.Return)
|
||||
{
|
||||
Rename(_renameTextBox.Text);
|
||||
StopRenaming();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (key == KeyboardKeys.Escape)
|
||||
{
|
||||
StopRenaming();
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnKeyDown(key);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
@@ -350,18 +415,18 @@ namespace FlaxEditor.Surface
|
||||
{
|
||||
cmOrder.ContextMenu.AddButton("Bring Forward", () =>
|
||||
{
|
||||
if(IndexInParent < Context.CommentCount-1)
|
||||
if (IndexInParent < Context.CommentCount - 1)
|
||||
IndexInParent++;
|
||||
OrderValue = IndexInParent;
|
||||
});
|
||||
cmOrder.ContextMenu.AddButton("Bring to Front", () =>
|
||||
{
|
||||
IndexInParent = Context.CommentCount-1;
|
||||
IndexInParent = Context.CommentCount - 1;
|
||||
OrderValue = IndexInParent;
|
||||
});
|
||||
cmOrder.ContextMenu.AddButton("Send Backward", () =>
|
||||
{
|
||||
if(IndexInParent > 0)
|
||||
if (IndexInParent > 0)
|
||||
IndexInParent--;
|
||||
OrderValue = IndexInParent;
|
||||
});
|
||||
|
||||
@@ -228,7 +228,7 @@ namespace FlaxEditor.Surface
|
||||
|
||||
// Draw icon
|
||||
bool hasConnections = box.HasAnyConnection;
|
||||
float alpha = box.Enabled ? 1.0f : 0.6f;
|
||||
float alpha = box.Enabled && box.IsActive ? 1.0f : 0.6f;
|
||||
Color color = box.CurrentTypeColor * alpha;
|
||||
var style = box.Surface.Style;
|
||||
SpriteHandle icon;
|
||||
|
||||
@@ -190,15 +190,7 @@ namespace FlaxEditor.Surface
|
||||
if (data == null || data.Length < 2)
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
var model = JsonConvert.DeserializeObject<DataModel>(data);
|
||||
return model?.Nodes != null && model.Nodes.Length != 0;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -215,7 +207,15 @@ namespace FlaxEditor.Surface
|
||||
try
|
||||
{
|
||||
// Load Mr Json
|
||||
var model = FlaxEngine.Json.JsonSerializer.Deserialize<DataModel>(data);
|
||||
DataModel model;
|
||||
try
|
||||
{
|
||||
model = FlaxEngine.Json.JsonSerializer.Deserialize<DataModel>(data);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (model.Nodes == null)
|
||||
model.Nodes = new DataModelNode[0];
|
||||
|
||||
|
||||
@@ -129,7 +129,12 @@ namespace FlaxEditor.Surface
|
||||
/// <param name="args">The drag drop arguments data.</param>
|
||||
protected virtual void HandleDragDropParameters(List<string> objects, DragDropEventArgs args)
|
||||
{
|
||||
var arch = GetParameterGetterNodeArchetype(out var groupId);
|
||||
// Try to get the setter node when holding the ALT key, otherwise get the getter node
|
||||
if (!Input.GetKey(KeyboardKeys.Alt) || !TryGetParameterSetterNodeArchetype(out var groupId, out var arch))
|
||||
{
|
||||
arch = GetParameterGetterNodeArchetype(out groupId);
|
||||
}
|
||||
|
||||
for (int i = 0; i < objects.Count; i++)
|
||||
{
|
||||
var parameter = GetParameter(objects[i]);
|
||||
@@ -156,5 +161,18 @@ namespace FlaxEditor.Surface
|
||||
groupId = 6;
|
||||
return Archetypes.Parameters.Nodes[0];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to get the parameter setter node archetype to use.
|
||||
/// </summary>
|
||||
/// <param name="groupId">The group ID.</param>
|
||||
/// <param name="archetype">The node archetype.</param>
|
||||
/// <returns>True if a setter node exists.</returns>
|
||||
protected virtual bool TryGetParameterSetterNodeArchetype(out ushort groupId, out NodeArchetype archetype)
|
||||
{
|
||||
groupId = 0;
|
||||
archetype = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,12 @@ namespace FlaxEditor.Surface
|
||||
return RootContext.GetParameter(name);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnParamReordered()
|
||||
{
|
||||
MarkAsEdited();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnParamCreated(SurfaceParameter param)
|
||||
{
|
||||
|
||||
@@ -350,6 +350,213 @@ namespace FlaxEditor.Surface
|
||||
}
|
||||
}
|
||||
|
||||
sealed class ReorderParamAction : IUndoAction
|
||||
{
|
||||
/// <summary>
|
||||
/// The window reference.
|
||||
/// </summary>
|
||||
public IVisjectSurfaceWindow Window;
|
||||
|
||||
/// <summary>
|
||||
/// The parameters editor for this action.
|
||||
/// </summary>
|
||||
public ParametersEditor Editor;
|
||||
|
||||
/// <summary>
|
||||
/// The old index the parameter was at.
|
||||
/// </summary>
|
||||
public int OldIndex;
|
||||
|
||||
/// <summary>
|
||||
/// The new index the parameter will be at.
|
||||
/// </summary>
|
||||
public int NewIndex;
|
||||
|
||||
/// <inheritdoc />
|
||||
public string ActionString => "Reorder Parameter";
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Dispose()
|
||||
{
|
||||
Window = null;
|
||||
Editor = null;
|
||||
}
|
||||
|
||||
public void Swap(int oldIdx, int newIdx)
|
||||
{
|
||||
if (oldIdx == newIdx)
|
||||
return; // ?
|
||||
|
||||
var parameters = Window.VisjectSurface.Parameters;
|
||||
if (newIdx > oldIdx)
|
||||
{
|
||||
for (int i = oldIdx; i < newIdx; i++)
|
||||
{
|
||||
SurfaceParameter old = parameters[i + 1];
|
||||
parameters[i + 1] = parameters[i];
|
||||
parameters[i] = old;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = oldIdx; i > newIdx; i--)
|
||||
{
|
||||
SurfaceParameter old = parameters[i - 1];
|
||||
parameters[i - 1] = parameters[i];
|
||||
parameters[i] = old;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Do()
|
||||
{
|
||||
Swap(OldIndex, NewIndex);
|
||||
Window.VisjectSurface.OnParamReordered();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Undo()
|
||||
{
|
||||
Swap(NewIndex, OldIndex);
|
||||
Window.VisjectSurface.OnParamReordered();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom draggable property name label that handles reordering visject parameters.
|
||||
/// </summary>
|
||||
/// <seealso cref="FlaxEditor.CustomEditors.GUI.DraggablePropertyNameLabel" />
|
||||
[HideInEditor]
|
||||
public class ParameterPropertyNameLabel : DraggablePropertyNameLabel
|
||||
{
|
||||
private ParametersEditor _editor;
|
||||
private IVisjectSurfaceWindow _window;
|
||||
private Rectangle _arrangeButtonRect;
|
||||
private bool _arrangeButtonInUse;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ParameterPropertyNameLabel(string name, ParametersEditor editor)
|
||||
: base(name)
|
||||
{
|
||||
_editor = editor;
|
||||
_window = _editor.Values[0] as IVisjectSurfaceWindow;
|
||||
_arrangeButtonRect = new Rectangle(2, 3, 12, 12);
|
||||
|
||||
// Extend margin of the label to support a dragging handle
|
||||
Margin m = Margin;
|
||||
m.Left += 16;
|
||||
Margin = m;
|
||||
}
|
||||
|
||||
private bool ArrangeAreaCheck(out int index, out Rectangle rect)
|
||||
{
|
||||
var child = _editor.ChildrenEditors[0];
|
||||
var container = child.Layout.ContainerControl;
|
||||
var mousePosition = container.PointFromScreen(Input.MouseScreenPosition);
|
||||
var barSidesExtend = 20.0f;
|
||||
var barHeight = 5.0f;
|
||||
var barCheckAreaHeight = 40.0f;
|
||||
var pos = mousePosition.Y + barCheckAreaHeight * 0.5f;
|
||||
|
||||
for (int i = 0; i < container.Children.Count / 2; i++)
|
||||
{
|
||||
var containerChild = container.Children[i * 2]; // times 2 to skip the value editor
|
||||
if (Mathf.IsInRange(pos, containerChild.Top, containerChild.Top + barCheckAreaHeight) || (i == 0 && pos < containerChild.Top))
|
||||
{
|
||||
index = i;
|
||||
var p1 = containerChild.UpperLeft;
|
||||
rect = new Rectangle(PointFromParent(p1) - new Float2(barSidesExtend * 0.5f, barHeight * 0.5f), Width + barSidesExtend, barHeight);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
var p2 = container.Children[((container.Children.Count / 2) - 1) * 2].BottomLeft;
|
||||
if (pos > p2.Y)
|
||||
{
|
||||
index = (container.Children.Count / 2) - 1;
|
||||
rect = new Rectangle(PointFromParent(p2) - new Float2(barSidesExtend * 0.5f, barHeight * 0.5f), Width + barSidesExtend, barHeight);
|
||||
return true;
|
||||
}
|
||||
|
||||
index = -1;
|
||||
rect = Rectangle.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Draw()
|
||||
{
|
||||
base.Draw();
|
||||
|
||||
var style = Style.Current;
|
||||
var mousePosition = PointFromScreen(Input.MouseScreenPosition);
|
||||
var dragBarColor = _arrangeButtonRect.Contains(mousePosition) ? style.Foreground : style.ForegroundGrey;
|
||||
Render2D.DrawSprite(Editor.Instance.Icons.DragBar12, _arrangeButtonRect, _arrangeButtonInUse ? Color.Orange : dragBarColor);
|
||||
if (_arrangeButtonInUse && ArrangeAreaCheck(out _, out var arrangeTargetRect))
|
||||
{
|
||||
Render2D.FillRectangle(arrangeTargetRect, style.Selection);
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left && _arrangeButtonRect.Contains(ref location))
|
||||
{
|
||||
_arrangeButtonInUse = true;
|
||||
Focus();
|
||||
StartMouseCapture();
|
||||
return true;
|
||||
}
|
||||
|
||||
return base.OnMouseDown(location, button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseUp(Float2 location, MouseButton button)
|
||||
{
|
||||
if (button == MouseButton.Left && _arrangeButtonInUse)
|
||||
{
|
||||
_arrangeButtonInUse = false;
|
||||
EndMouseCapture();
|
||||
ArrangeAreaCheck(out var index, out _);
|
||||
var action = new ReorderParamAction
|
||||
{
|
||||
OldIndex = (int)Tag,
|
||||
NewIndex = index,
|
||||
Window = _window,
|
||||
Editor = _editor
|
||||
};
|
||||
action.Do();
|
||||
_window.Undo.AddAction(action);
|
||||
}
|
||||
|
||||
return base.OnMouseUp(location, button);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void OnLostFocus()
|
||||
{
|
||||
if (_arrangeButtonInUse)
|
||||
{
|
||||
_arrangeButtonInUse = false;
|
||||
EndMouseCapture();
|
||||
}
|
||||
|
||||
base.OnLostFocus();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnSizeChanged()
|
||||
{
|
||||
base.OnSizeChanged();
|
||||
|
||||
// Center the drag button vertically
|
||||
_arrangeButtonRect = new Rectangle(2, Mathf.Ceil((Height - 12) * 0.5f) + 1, 12, 12);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom editor for editing Visject Surface parameters collection.
|
||||
/// </summary>
|
||||
@@ -431,10 +638,10 @@ namespace FlaxEditor.Surface
|
||||
attributes
|
||||
);
|
||||
|
||||
var propertyLabel = new DraggablePropertyNameLabel(name)
|
||||
var propertyLabel = new ParameterPropertyNameLabel(name, this)
|
||||
{
|
||||
Tag = pIndex,
|
||||
Drag = OnDragParameter
|
||||
Drag = OnDragParameter,
|
||||
};
|
||||
if (!p.IsPublic)
|
||||
propertyLabel.TextColor = propertyLabel.TextColor.RGBMultiplied(0.7f);
|
||||
|
||||
@@ -187,6 +187,14 @@ namespace FlaxEditor.Surface
|
||||
return Archetypes.Parameters.Nodes[2];
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override bool TryGetParameterSetterNodeArchetype(out ushort groupId, out NodeArchetype archetype)
|
||||
{
|
||||
groupId = 6;
|
||||
archetype = Archetypes.Parameters.Nodes[3];
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnShowPrimaryMenu(VisjectCM activeCM, Float2 location, Box startBox)
|
||||
{
|
||||
|
||||
@@ -82,7 +82,7 @@ namespace FlaxEditor.Tools.Foliage
|
||||
}
|
||||
}
|
||||
|
||||
[EditorOrder(20), EditorDisplay("Model"), Collection(ReadOnly = true), Tooltip("Model materials override collection. Can be used to change a specific material of the mesh to the custom one without editing the asset.")]
|
||||
[EditorOrder(20), EditorDisplay("Model"), Collection(CanResize = true), Tooltip("Model materials override collection. Can be used to change a specific material of the mesh to the custom one without editing the asset.")]
|
||||
public MaterialBase[] Materials
|
||||
{
|
||||
get
|
||||
|
||||
@@ -36,7 +36,10 @@ namespace FlaxEditor.Utilities
|
||||
public void GatherSceneData()
|
||||
{
|
||||
if (HasData)
|
||||
throw new InvalidOperationException("DuplicateScenes has already gathered scene data.");
|
||||
{
|
||||
Editor.LogError("DuplicateScenes has already gathered scene data.");
|
||||
return;
|
||||
}
|
||||
Profiler.BeginEvent("DuplicateScenes.GatherSceneData");
|
||||
|
||||
Editor.Log("Collecting scene data");
|
||||
@@ -47,7 +50,8 @@ namespace FlaxEditor.Utilities
|
||||
if (scenesCount == 0)
|
||||
{
|
||||
Profiler.EndEvent();
|
||||
throw new InvalidOperationException("Cannot gather scene data. No scene loaded.");
|
||||
Editor.LogWarning("Cannot gather scene data. No scene loaded.");
|
||||
return;
|
||||
}
|
||||
var sceneIds = new Guid[scenesCount];
|
||||
for (int i = 0; i < scenesCount; i++)
|
||||
@@ -72,7 +76,8 @@ namespace FlaxEditor.Utilities
|
||||
if (Level.UnloadAllScenes())
|
||||
{
|
||||
Profiler.EndEvent();
|
||||
throw new Exception("Failed to unload scenes.");
|
||||
Editor.LogError("Failed to unload scenes.");
|
||||
return;
|
||||
}
|
||||
FlaxEngine.Scripting.FlushRemovedObjects();
|
||||
|
||||
@@ -82,7 +87,8 @@ namespace FlaxEditor.Utilities
|
||||
if (noScenes != null && noScenes.Length != 0)
|
||||
{
|
||||
Profiler.EndEvent();
|
||||
throw new Exception("Failed to unload scenes.");
|
||||
Editor.LogError("Failed to unload scenes.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,7 +102,10 @@ namespace FlaxEditor.Utilities
|
||||
public void CreateScenes()
|
||||
{
|
||||
if (!HasData)
|
||||
throw new InvalidOperationException("DuplicateScenes has not gathered scene data yet.");
|
||||
{
|
||||
Editor.LogError("DuplicateScenes has not gathered scene data yet.");
|
||||
return;
|
||||
}
|
||||
Profiler.BeginEvent("DuplicateScenes.CreateScenes");
|
||||
|
||||
Editor.Log("Creating scenes");
|
||||
@@ -110,7 +119,8 @@ namespace FlaxEditor.Utilities
|
||||
if (scene == null)
|
||||
{
|
||||
Profiler.EndEvent();
|
||||
throw new Exception("Failed to deserialize scene");
|
||||
Editor.LogError("Failed to deserialize scene.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +141,8 @@ namespace FlaxEditor.Utilities
|
||||
if (Level.UnloadAllScenes())
|
||||
{
|
||||
Profiler.EndEvent();
|
||||
throw new Exception("Failed to unload scenes.");
|
||||
Editor.LogError("Failed to unload scenes.");
|
||||
return;
|
||||
}
|
||||
FlaxEngine.Scripting.FlushRemovedObjects();
|
||||
Editor.WipeOutLeftoverSceneObjects();
|
||||
@@ -145,7 +156,10 @@ namespace FlaxEditor.Utilities
|
||||
public void RestoreSceneData()
|
||||
{
|
||||
if (!HasData)
|
||||
throw new InvalidOperationException("DuplicateScenes has not gathered scene data yet.");
|
||||
{
|
||||
Editor.LogError("DuplicateScenes has not gathered scene data yet.");
|
||||
return;
|
||||
}
|
||||
Profiler.BeginEvent("DuplicateScenes.RestoreSceneData");
|
||||
|
||||
// Deserialize old scenes
|
||||
@@ -155,8 +169,8 @@ namespace FlaxEditor.Utilities
|
||||
var scene = Level.LoadSceneFromBytes(data.Bytes);
|
||||
if (scene == null)
|
||||
{
|
||||
Profiler.EndEvent();
|
||||
throw new Exception("Failed to deserialize scene");
|
||||
Editor.LogError("Failed to restore scene");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Restore `dirty` state
|
||||
|
||||
@@ -1,131 +0,0 @@
|
||||
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
||||
|
||||
#include "ScreenUtilities.h"
|
||||
#include "Engine/Core/Math/Vector2.h"
|
||||
#include "Engine/Core/Delegate.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
|
||||
Delegate<Color32> ScreenUtilities::PickColorDone;
|
||||
|
||||
#if PLATFORM_WINDOWS
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#pragma comment(lib, "Gdi32.lib")
|
||||
|
||||
static HHOOK MouseCallbackHook;
|
||||
|
||||
LRESULT CALLBACK OnScreenUtilsMouseCallback(_In_ int nCode, _In_ WPARAM wParam, _In_ LPARAM lParam)
|
||||
{
|
||||
if (nCode >= 0 && wParam == WM_LBUTTONDOWN)
|
||||
{
|
||||
UnhookWindowsHookEx(MouseCallbackHook);
|
||||
|
||||
// Push event with the picked color
|
||||
const Float2 cursorPos = Platform::GetMousePosition();
|
||||
const Color32 colorPicked = ScreenUtilities::GetColorAt(cursorPos);
|
||||
ScreenUtilities::PickColorDone(colorPicked);
|
||||
return 1;
|
||||
}
|
||||
return CallNextHookEx(NULL, nCode, wParam, lParam);
|
||||
}
|
||||
|
||||
Color32 ScreenUtilities::GetColorAt(const Float2& pos)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
HDC deviceContext = GetDC(NULL);
|
||||
COLORREF color = GetPixel(deviceContext, (int)pos.X, (int)pos.Y);
|
||||
ReleaseDC(NULL, deviceContext);
|
||||
return Color32(GetRValue(color), GetGValue(color), GetBValue(color), 255);
|
||||
}
|
||||
|
||||
void ScreenUtilities::PickColor()
|
||||
{
|
||||
MouseCallbackHook = SetWindowsHookEx(WH_MOUSE_LL, OnScreenUtilsMouseCallback, NULL, NULL);
|
||||
if (MouseCallbackHook == NULL)
|
||||
{
|
||||
LOG(Warning, "Failed to set mouse hook.");
|
||||
LOG(Warning, "Error: {0}", GetLastError());
|
||||
}
|
||||
}
|
||||
|
||||
#elif PLATFORM_LINUX
|
||||
|
||||
#include "Engine/Platform/Linux/LinuxPlatform.h"
|
||||
#include "Engine/Platform/Linux/IncludeX11.h"
|
||||
|
||||
Color32 ScreenUtilities::GetColorAt(const Float2& pos)
|
||||
{
|
||||
X11::XColor color;
|
||||
|
||||
X11::Display* display = (X11::Display*) LinuxPlatform::GetXDisplay();
|
||||
int defaultScreen = X11::XDefaultScreen(display);
|
||||
|
||||
X11::XImage* image;
|
||||
image = X11::XGetImage(display, X11::XRootWindow(display, defaultScreen), (int)pos.X, (int)pos.Y, 1, 1, AllPlanes, XYPixmap);
|
||||
color.pixel = XGetPixel(image, 0, 0);
|
||||
X11::XFree(image);
|
||||
|
||||
X11::XQueryColor(display, X11::XDefaultColormap(display, defaultScreen), &color);
|
||||
|
||||
Color32 outputColor;
|
||||
outputColor.R = color.red / 256;
|
||||
outputColor.G = color.green / 256;
|
||||
outputColor.B = color.blue / 256;
|
||||
outputColor.A = 255;
|
||||
return outputColor;
|
||||
}
|
||||
|
||||
void OnScreenUtilsXEventCallback(void* eventPtr)
|
||||
{
|
||||
X11::XEvent* event = (X11::XEvent*) eventPtr;
|
||||
X11::Display* display = (X11::Display*)LinuxPlatform::GetXDisplay();
|
||||
if (event->type == ButtonPress)
|
||||
{
|
||||
const Float2 cursorPos = Platform::GetMousePosition();
|
||||
const Color32 colorPicked = ScreenUtilities::GetColorAt(cursorPos);
|
||||
X11::XUngrabPointer(display, CurrentTime);
|
||||
ScreenUtilities::PickColorDone(colorPicked);
|
||||
LinuxPlatform::xEventRecieved.Unbind(OnScreenUtilsXEventCallback);
|
||||
}
|
||||
}
|
||||
|
||||
void ScreenUtilities::PickColor()
|
||||
{
|
||||
PROFILE_CPU();
|
||||
X11::Display* display = (X11::Display*) LinuxPlatform::GetXDisplay();
|
||||
X11::Window rootWindow = X11::XRootWindow(display, X11::XDefaultScreen(display));
|
||||
|
||||
X11::Cursor cursor = XCreateFontCursor(display, 130);
|
||||
int grabbedPointer = X11::XGrabPointer(display, rootWindow, 0, ButtonPressMask, GrabModeAsync, GrabModeAsync, rootWindow, cursor, CurrentTime);
|
||||
if (grabbedPointer != GrabSuccess)
|
||||
{
|
||||
LOG(Error, "Failed to grab cursor for events.");
|
||||
X11::XFreeCursor(display, cursor);
|
||||
return;
|
||||
}
|
||||
|
||||
X11::XFreeCursor(display, cursor);
|
||||
LinuxPlatform::xEventRecieved.Bind(OnScreenUtilsXEventCallback);
|
||||
}
|
||||
|
||||
#elif PLATFORM_MAC
|
||||
|
||||
#include <Cocoa/Cocoa.h>
|
||||
#include <AppKit/AppKit.h>
|
||||
|
||||
Color32 ScreenUtilities::GetColorAt(const Float2& pos)
|
||||
{
|
||||
// TODO: implement ScreenUtilities for macOS
|
||||
return { 0, 0, 0, 255 };
|
||||
}
|
||||
|
||||
void ScreenUtilities::PickColor()
|
||||
{
|
||||
// This is what C# calls to start the color picking sequence
|
||||
// This should stop mouse clicks from working for one click, and that click is on the selected color
|
||||
// There is a class called NSColorSample that might implement that for you, but maybe not.
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -2,32 +2,4 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Engine/Core/Types/BaseTypes.h"
|
||||
#include "Engine/Core/Math/Color32.h"
|
||||
#include "Engine/Core/Math/Vector2.h"
|
||||
#include "Engine/Core/Delegate.h"
|
||||
|
||||
/// <summary>
|
||||
/// Platform-dependent screen utilities.
|
||||
/// </summary>
|
||||
API_CLASS(Static) class FLAXENGINE_API ScreenUtilities
|
||||
{
|
||||
DECLARE_SCRIPTING_TYPE_MINIMAL(ScreenUtilities);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the pixel color at the specified coordinates.
|
||||
/// </summary>
|
||||
/// <param name="pos">Screen-space coordinate to read.</param>
|
||||
/// <returns>Pixel color at the specified coordinates.</returns>
|
||||
API_FUNCTION() static Color32 GetColorAt(const Float2& pos);
|
||||
|
||||
/// <summary>
|
||||
/// Starts async color picking. Color will be returned through PickColorDone event when the actions ends (user selected the final color with a mouse). When action is active, GetColorAt can be used to read the current value.
|
||||
/// </summary>
|
||||
API_FUNCTION() static void PickColor();
|
||||
|
||||
/// <summary>
|
||||
/// Called when PickColor action is finished.
|
||||
/// </summary>
|
||||
API_EVENT() static Delegate<Color32> PickColorDone;
|
||||
};
|
||||
#include "Engine/Platform/ScreenUtilities.h"
|
||||
|
||||
@@ -137,19 +137,19 @@ namespace FlaxEditor.Viewport
|
||||
if (useProjectCache)
|
||||
{
|
||||
// Initialize snapping enabled from cached values
|
||||
if (editor.ProjectCache.TryGetCustomData("TranslateSnapState", out var cachedState))
|
||||
transformGizmo.TranslationSnapEnable = bool.Parse(cachedState);
|
||||
if (editor.ProjectCache.TryGetCustomData("RotationSnapState", out cachedState))
|
||||
transformGizmo.RotationSnapEnabled = bool.Parse(cachedState);
|
||||
if (editor.ProjectCache.TryGetCustomData("ScaleSnapState", out cachedState))
|
||||
transformGizmo.ScaleSnapEnabled = bool.Parse(cachedState);
|
||||
if (editor.ProjectCache.TryGetCustomData("TranslateSnapValue", out cachedState))
|
||||
transformGizmo.TranslationSnapValue = float.Parse(cachedState);
|
||||
if (editor.ProjectCache.TryGetCustomData("RotationSnapValue", out cachedState))
|
||||
transformGizmo.RotationSnapValue = float.Parse(cachedState);
|
||||
if (editor.ProjectCache.TryGetCustomData("ScaleSnapValue", out cachedState))
|
||||
transformGizmo.ScaleSnapValue = float.Parse(cachedState);
|
||||
if (editor.ProjectCache.TryGetCustomData("TransformSpaceState", out cachedState) && Enum.TryParse(cachedState, out TransformGizmoBase.TransformSpace space))
|
||||
if (editor.ProjectCache.TryGetCustomData("TranslateSnapState", out bool cachedBool))
|
||||
transformGizmo.TranslationSnapEnable = cachedBool;
|
||||
if (editor.ProjectCache.TryGetCustomData("RotationSnapState", out cachedBool))
|
||||
transformGizmo.RotationSnapEnabled = cachedBool;
|
||||
if (editor.ProjectCache.TryGetCustomData("ScaleSnapState", out cachedBool))
|
||||
transformGizmo.ScaleSnapEnabled = cachedBool;
|
||||
if (editor.ProjectCache.TryGetCustomData("TranslateSnapValue", out float cachedFloat))
|
||||
transformGizmo.TranslationSnapValue = cachedFloat;
|
||||
if (editor.ProjectCache.TryGetCustomData("RotationSnapValue", out cachedFloat))
|
||||
transformGizmo.RotationSnapValue = cachedFloat;
|
||||
if (editor.ProjectCache.TryGetCustomData("ScaleSnapValue", out cachedFloat))
|
||||
transformGizmo.ScaleSnapValue = cachedFloat;
|
||||
if (editor.ProjectCache.TryGetCustomData("TransformSpaceState", out string cachedText) && Enum.TryParse(cachedText, out TransformGizmoBase.TransformSpace space))
|
||||
transformGizmo.ActiveTransformSpace = space;
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ namespace FlaxEditor.Viewport
|
||||
{
|
||||
transformGizmo.ScaleSnapEnabled = !transformGizmo.ScaleSnapEnabled;
|
||||
if (useProjectCache)
|
||||
editor.ProjectCache.SetCustomData("ScaleSnapState", transformGizmo.ScaleSnapEnabled.ToString());
|
||||
editor.ProjectCache.SetCustomData("ScaleSnapState", transformGizmo.ScaleSnapEnabled);
|
||||
};
|
||||
var scaleSnappingCM = new ContextMenu();
|
||||
var scaleSnapping = new ViewportWidgetButton(transformGizmo.ScaleSnapValue.ToString(), SpriteHandle.Invalid, scaleSnappingCM)
|
||||
@@ -200,7 +200,7 @@ namespace FlaxEditor.Viewport
|
||||
transformGizmo.ScaleSnapValue = v;
|
||||
scaleSnapping.Text = v.ToString();
|
||||
if (useProjectCache)
|
||||
editor.ProjectCache.SetCustomData("ScaleSnapValue", transformGizmo.ScaleSnapValue.ToString("N"));
|
||||
editor.ProjectCache.SetCustomData("ScaleSnapValue", transformGizmo.ScaleSnapValue);
|
||||
};
|
||||
scaleSnappingCM.VisibleChanged += control =>
|
||||
{
|
||||
@@ -231,7 +231,7 @@ namespace FlaxEditor.Viewport
|
||||
{
|
||||
transformGizmo.RotationSnapEnabled = !transformGizmo.RotationSnapEnabled;
|
||||
if (useProjectCache)
|
||||
editor.ProjectCache.SetCustomData("RotationSnapState", transformGizmo.RotationSnapEnabled.ToString());
|
||||
editor.ProjectCache.SetCustomData("RotationSnapState", transformGizmo.RotationSnapEnabled);
|
||||
};
|
||||
var rotateSnappingCM = new ContextMenu();
|
||||
var rotateSnapping = new ViewportWidgetButton(transformGizmo.RotationSnapValue.ToString(), SpriteHandle.Invalid, rotateSnappingCM)
|
||||
@@ -250,7 +250,7 @@ namespace FlaxEditor.Viewport
|
||||
transformGizmo.RotationSnapValue = v;
|
||||
rotateSnapping.Text = v.ToString();
|
||||
if (useProjectCache)
|
||||
editor.ProjectCache.SetCustomData("RotationSnapValue", transformGizmo.RotationSnapValue.ToString("N"));
|
||||
editor.ProjectCache.SetCustomData("RotationSnapValue", transformGizmo.RotationSnapValue);
|
||||
};
|
||||
rotateSnappingCM.VisibleChanged += control =>
|
||||
{
|
||||
@@ -281,7 +281,7 @@ namespace FlaxEditor.Viewport
|
||||
{
|
||||
transformGizmo.TranslationSnapEnable = !transformGizmo.TranslationSnapEnable;
|
||||
if (useProjectCache)
|
||||
editor.ProjectCache.SetCustomData("TranslateSnapState", transformGizmo.TranslationSnapEnable.ToString());
|
||||
editor.ProjectCache.SetCustomData("TranslateSnapState", transformGizmo.TranslationSnapEnable);
|
||||
};
|
||||
var translateSnappingCM = new ContextMenu();
|
||||
var translateSnapping = new ViewportWidgetButton(transformGizmo.TranslationSnapValue.ToString(), SpriteHandle.Invalid, translateSnappingCM)
|
||||
@@ -307,7 +307,7 @@ namespace FlaxEditor.Viewport
|
||||
else
|
||||
translateSnapping.Text = v.ToString();
|
||||
if (useProjectCache)
|
||||
editor.ProjectCache.SetCustomData("TranslateSnapValue", transformGizmo.TranslationSnapValue.ToString("N"));
|
||||
editor.ProjectCache.SetCustomData("TranslateSnapValue", transformGizmo.TranslationSnapValue);
|
||||
};
|
||||
translateSnappingCM.VisibleChanged += control =>
|
||||
{
|
||||
@@ -360,11 +360,36 @@ namespace FlaxEditor.Viewport
|
||||
};
|
||||
|
||||
// Setup input actions
|
||||
viewport.InputActions.Add(options => options.TranslateMode, () => transformGizmo.ActiveMode = TransformGizmoBase.Mode.Translate);
|
||||
viewport.InputActions.Add(options => options.RotateMode, () => transformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate);
|
||||
viewport.InputActions.Add(options => options.ScaleMode, () => transformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale);
|
||||
viewport.InputActions.Add(options => options.TranslateMode, () =>
|
||||
{
|
||||
viewport.GetInput(out var input);
|
||||
if (input.IsMouseRightDown)
|
||||
return;
|
||||
|
||||
transformGizmo.ActiveMode = TransformGizmoBase.Mode.Translate;
|
||||
});
|
||||
viewport.InputActions.Add(options => options.RotateMode, () =>
|
||||
{
|
||||
viewport.GetInput(out var input);
|
||||
if (input.IsMouseRightDown)
|
||||
return;
|
||||
|
||||
transformGizmo.ActiveMode = TransformGizmoBase.Mode.Rotate;
|
||||
});
|
||||
viewport.InputActions.Add(options => options.ScaleMode, () =>
|
||||
{
|
||||
viewport.GetInput(out var input);
|
||||
if (input.IsMouseRightDown)
|
||||
return;
|
||||
|
||||
transformGizmo.ActiveMode = TransformGizmoBase.Mode.Scale;
|
||||
});
|
||||
viewport.InputActions.Add(options => options.ToggleTransformSpace, () =>
|
||||
{
|
||||
viewport.GetInput(out var input);
|
||||
if (input.IsMouseRightDown)
|
||||
return;
|
||||
|
||||
transformGizmo.ToggleTransformSpace();
|
||||
if (useProjectCache)
|
||||
editor.ProjectCache.SetCustomData("TransformSpaceState", transformGizmo.ActiveTransformSpace.ToString());
|
||||
|
||||
@@ -155,18 +155,22 @@ namespace FlaxEditor.Viewport
|
||||
private float _movementSpeed;
|
||||
private float _minMovementSpeed;
|
||||
private float _maxMovementSpeed;
|
||||
#if !PLATFORM_SDL
|
||||
private float _mouseAccelerationScale;
|
||||
private bool _useMouseFiltering;
|
||||
private bool _useMouseAcceleration;
|
||||
#endif
|
||||
|
||||
// Input
|
||||
|
||||
internal bool _disableInputUpdate;
|
||||
private bool _isControllingMouse, _isViewportControllingMouse, _wasVirtualMouseRightDown, _isVirtualMouseRightDown;
|
||||
private int _deltaFilteringStep;
|
||||
private Float2 _startPos;
|
||||
#if !PLATFORM_SDL
|
||||
private Float2 _mouseDeltaLast;
|
||||
private int _deltaFilteringStep;
|
||||
private Float2[] _deltaFilteringBuffer = new Float2[FpsCameraFilteringFrames];
|
||||
#endif
|
||||
|
||||
/// <summary>
|
||||
/// The previous input (from the previous update).
|
||||
@@ -522,10 +526,11 @@ namespace FlaxEditor.Viewport
|
||||
: base(task)
|
||||
{
|
||||
_editor = Editor.Instance;
|
||||
|
||||
#if !PLATFORM_SDL
|
||||
_mouseAccelerationScale = 0.1f;
|
||||
_useMouseFiltering = false;
|
||||
_useMouseAcceleration = false;
|
||||
#endif
|
||||
_camera = camera;
|
||||
if (_camera != null)
|
||||
_camera.Viewport = this;
|
||||
@@ -540,30 +545,30 @@ namespace FlaxEditor.Viewport
|
||||
}
|
||||
|
||||
// Initialize camera values from cache
|
||||
if (_editor.ProjectCache.TryGetCustomData("CameraMovementSpeedValue", out var cachedState))
|
||||
MovementSpeed = float.Parse(cachedState);
|
||||
if (_editor.ProjectCache.TryGetCustomData("CameraMinMovementSpeedValue", out cachedState))
|
||||
_minMovementSpeed = float.Parse(cachedState);
|
||||
if (_editor.ProjectCache.TryGetCustomData("CameraMaxMovementSpeedValue", out cachedState))
|
||||
_maxMovementSpeed = float.Parse(cachedState);
|
||||
if (_editor.ProjectCache.TryGetCustomData("UseCameraEasingState", out cachedState))
|
||||
_useCameraEasing = bool.Parse(cachedState);
|
||||
if (_editor.ProjectCache.TryGetCustomData("CameraPanningSpeedValue", out cachedState))
|
||||
_panningSpeed = float.Parse(cachedState);
|
||||
if (_editor.ProjectCache.TryGetCustomData("CameraInvertPanningState", out cachedState))
|
||||
_invertPanning = bool.Parse(cachedState);
|
||||
if (_editor.ProjectCache.TryGetCustomData("CameraRelativePanningState", out cachedState))
|
||||
_relativePanning = bool.Parse(cachedState);
|
||||
if (_editor.ProjectCache.TryGetCustomData("CameraOrthographicState", out cachedState))
|
||||
_isOrtho = bool.Parse(cachedState);
|
||||
if (_editor.ProjectCache.TryGetCustomData("CameraOrthographicSizeValue", out cachedState))
|
||||
_orthoSize = float.Parse(cachedState);
|
||||
if (_editor.ProjectCache.TryGetCustomData("CameraFieldOfViewValue", out cachedState))
|
||||
_fieldOfView = float.Parse(cachedState);
|
||||
if (_editor.ProjectCache.TryGetCustomData("CameraNearPlaneValue", out cachedState))
|
||||
_nearPlane = float.Parse(cachedState);
|
||||
if (_editor.ProjectCache.TryGetCustomData("CameraFarPlaneValue", out cachedState))
|
||||
_farPlane = float.Parse(cachedState);
|
||||
if (_editor.ProjectCache.TryGetCustomData("CameraMovementSpeedValue", out float cachedFloat))
|
||||
MovementSpeed = cachedFloat;
|
||||
if (_editor.ProjectCache.TryGetCustomData("CameraMinMovementSpeedValue", out cachedFloat))
|
||||
_minMovementSpeed = cachedFloat;
|
||||
if (_editor.ProjectCache.TryGetCustomData("CameraMaxMovementSpeedValue", out cachedFloat))
|
||||
_maxMovementSpeed = cachedFloat;
|
||||
if (_editor.ProjectCache.TryGetCustomData("UseCameraEasingState", out bool cachedBool))
|
||||
_useCameraEasing = cachedBool;
|
||||
if (_editor.ProjectCache.TryGetCustomData("CameraPanningSpeedValue", out cachedFloat))
|
||||
_panningSpeed = cachedFloat;
|
||||
if (_editor.ProjectCache.TryGetCustomData("CameraInvertPanningState", out cachedBool))
|
||||
_invertPanning = cachedBool;
|
||||
if (_editor.ProjectCache.TryGetCustomData("CameraRelativePanningState", out cachedBool))
|
||||
_relativePanning = cachedBool;
|
||||
if (_editor.ProjectCache.TryGetCustomData("CameraOrthographicState", out cachedBool))
|
||||
_isOrtho = cachedBool;
|
||||
if (_editor.ProjectCache.TryGetCustomData("CameraOrthographicSizeValue", out cachedFloat))
|
||||
_orthoSize = cachedFloat;
|
||||
if (_editor.ProjectCache.TryGetCustomData("CameraFieldOfViewValue", out cachedFloat))
|
||||
_fieldOfView = cachedFloat;
|
||||
if (_editor.ProjectCache.TryGetCustomData("CameraNearPlaneValue", out cachedFloat))
|
||||
_nearPlane = cachedFloat;
|
||||
if (_editor.ProjectCache.TryGetCustomData("CameraFarPlaneValue", out cachedFloat))
|
||||
_farPlane = cachedFloat;
|
||||
|
||||
OnCameraMovementProgressChanged();
|
||||
|
||||
@@ -1041,7 +1046,7 @@ namespace FlaxEditor.Viewport
|
||||
MovementSpeed = value;
|
||||
|
||||
OnCameraMovementProgressChanged();
|
||||
_editor.ProjectCache.SetCustomData("CameraMovementSpeedValue", _movementSpeed.ToString());
|
||||
_editor.ProjectCache.SetCustomData("CameraMovementSpeedValue", _movementSpeed);
|
||||
}
|
||||
|
||||
private void OnMinMovementSpeedChanged(FloatValueBox control)
|
||||
@@ -1053,7 +1058,7 @@ namespace FlaxEditor.Viewport
|
||||
MovementSpeed = value;
|
||||
|
||||
OnCameraMovementProgressChanged();
|
||||
_editor.ProjectCache.SetCustomData("CameraMinMovementSpeedValue", _minMovementSpeed.ToString());
|
||||
_editor.ProjectCache.SetCustomData("CameraMinMovementSpeedValue", _minMovementSpeed);
|
||||
}
|
||||
|
||||
private void OnMaxMovementSpeedChanged(FloatValueBox control)
|
||||
@@ -1065,7 +1070,7 @@ namespace FlaxEditor.Viewport
|
||||
MovementSpeed = value;
|
||||
|
||||
OnCameraMovementProgressChanged();
|
||||
_editor.ProjectCache.SetCustomData("CameraMaxMovementSpeedValue", _maxMovementSpeed.ToString());
|
||||
_editor.ProjectCache.SetCustomData("CameraMaxMovementSpeedValue", _maxMovementSpeed);
|
||||
}
|
||||
|
||||
private void OnCameraEasingToggled(Control control)
|
||||
@@ -1073,25 +1078,25 @@ namespace FlaxEditor.Viewport
|
||||
_useCameraEasing = !_useCameraEasing;
|
||||
|
||||
OnCameraMovementProgressChanged();
|
||||
_editor.ProjectCache.SetCustomData("UseCameraEasingState", _useCameraEasing.ToString());
|
||||
_editor.ProjectCache.SetCustomData("UseCameraEasingState", _useCameraEasing);
|
||||
}
|
||||
|
||||
private void OnPanningSpeedChanged(FloatValueBox control)
|
||||
{
|
||||
_panningSpeed = control.Value;
|
||||
_editor.ProjectCache.SetCustomData("CameraPanningSpeedValue", _panningSpeed.ToString());
|
||||
_editor.ProjectCache.SetCustomData("CameraPanningSpeedValue", _panningSpeed);
|
||||
}
|
||||
|
||||
private void OnRelativePanningToggled(Control control)
|
||||
{
|
||||
_relativePanning = !_relativePanning;
|
||||
_editor.ProjectCache.SetCustomData("CameraRelativePanningState", _relativePanning.ToString());
|
||||
_editor.ProjectCache.SetCustomData("CameraRelativePanningState", _relativePanning);
|
||||
}
|
||||
|
||||
private void OnInvertPanningToggled(Control control)
|
||||
{
|
||||
_invertPanning = !_invertPanning;
|
||||
_editor.ProjectCache.SetCustomData("CameraInvertPanningState", _invertPanning.ToString());
|
||||
_editor.ProjectCache.SetCustomData("CameraInvertPanningState", _invertPanning);
|
||||
}
|
||||
|
||||
|
||||
@@ -1104,7 +1109,7 @@ namespace FlaxEditor.Viewport
|
||||
private void OnFieldOfViewChanged(FloatValueBox control)
|
||||
{
|
||||
_fieldOfView = control.Value;
|
||||
_editor.ProjectCache.SetCustomData("CameraFieldOfViewValue", _fieldOfView.ToString());
|
||||
_editor.ProjectCache.SetCustomData("CameraFieldOfViewValue", _fieldOfView);
|
||||
}
|
||||
|
||||
private void OnOrthographicModeToggled(Control control)
|
||||
@@ -1120,25 +1125,25 @@ namespace FlaxEditor.Viewport
|
||||
OrientViewport(ref orient);
|
||||
}
|
||||
|
||||
_editor.ProjectCache.SetCustomData("CameraOrthographicState", _isOrtho.ToString());
|
||||
_editor.ProjectCache.SetCustomData("CameraOrthographicState", _isOrtho);
|
||||
}
|
||||
|
||||
private void OnOrthographicSizeChanged(FloatValueBox control)
|
||||
{
|
||||
_orthoSize = control.Value;
|
||||
_editor.ProjectCache.SetCustomData("CameraOrthographicSizeValue", _orthoSize.ToString());
|
||||
_editor.ProjectCache.SetCustomData("CameraOrthographicSizeValue", _orthoSize);
|
||||
}
|
||||
|
||||
private void OnNearPlaneChanged(FloatValueBox control)
|
||||
{
|
||||
_nearPlane = control.Value;
|
||||
_editor.ProjectCache.SetCustomData("CameraNearPlaneValue", _nearPlane.ToString());
|
||||
_editor.ProjectCache.SetCustomData("CameraNearPlaneValue", _nearPlane);
|
||||
}
|
||||
|
||||
private void OnFarPlaneChanged(FloatValueBox control)
|
||||
{
|
||||
_farPlane = control.Value;
|
||||
_editor.ProjectCache.SetCustomData("CameraFarPlaneValue", _farPlane.ToString());
|
||||
_editor.ProjectCache.SetCustomData("CameraFarPlaneValue", _farPlane);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1217,7 +1222,7 @@ namespace FlaxEditor.Viewport
|
||||
|
||||
var speed = Mathf.Lerp(_minMovementSpeed, _maxMovementSpeed, progress);
|
||||
MovementSpeed = (float)Math.Round(speed, 3);
|
||||
_editor.ProjectCache.SetCustomData("CameraMovementSpeedValue", _movementSpeed.ToString());
|
||||
_editor.ProjectCache.SetCustomData("CameraMovementSpeedValue", _movementSpeed);
|
||||
}
|
||||
|
||||
private void OnEditorOptionsChanged(EditorOptions options)
|
||||
@@ -1420,7 +1425,9 @@ namespace FlaxEditor.Viewport
|
||||
// Hide cursor and start tracking mouse movement
|
||||
win.StartTrackingMouse(false);
|
||||
win.Cursor = CursorType.Hidden;
|
||||
win.MouseMoveRelative += OnMouseMoveRelative;
|
||||
|
||||
#if !PLATFORM_SDL
|
||||
// Center mouse position if it's too close to the edge
|
||||
var size = Size;
|
||||
var center = Float2.Round(size * 0.5f);
|
||||
@@ -1429,6 +1436,7 @@ namespace FlaxEditor.Viewport
|
||||
_viewMousePos = center;
|
||||
win.MousePosition = PointToWindow(_viewMousePos);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1440,6 +1448,7 @@ namespace FlaxEditor.Viewport
|
||||
// Restore cursor and stop tracking mouse movement
|
||||
win.Cursor = CursorType.Default;
|
||||
win.EndTrackingMouse();
|
||||
win.MouseMoveRelative -= OnMouseMoveRelative;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1544,6 +1553,14 @@ namespace FlaxEditor.Viewport
|
||||
else
|
||||
EndMouseCapture();
|
||||
}
|
||||
#if PLATFORM_SDL
|
||||
bool useMouse = IsControllingMouse || true;
|
||||
_prevInput = _input;
|
||||
if (canUseInput && ContainsFocus)
|
||||
_input.Gather(win.Window, useMouse, ref _prevInput);
|
||||
else
|
||||
_input.Clear();
|
||||
#else
|
||||
bool useMouse = IsControllingMouse || (Mathf.IsInRange(_viewMousePos.X, 0, Width) && Mathf.IsInRange(_viewMousePos.Y, 0, Height));
|
||||
_prevInput = _input;
|
||||
var hit = GetChildAt(_viewMousePos, c => c.Visible && !(c is CanvasRootControl) && !(c is UIEditorRoot));
|
||||
@@ -1551,6 +1568,7 @@ namespace FlaxEditor.Viewport
|
||||
_input.Gather(win.Window, useMouse, ref _prevInput);
|
||||
else
|
||||
_input.Clear();
|
||||
#endif
|
||||
|
||||
// Track controlling mouse state change
|
||||
bool wasControllingMouse = _prevInput.IsControllingMouse;
|
||||
@@ -1659,6 +1677,10 @@ namespace FlaxEditor.Viewport
|
||||
if (_input.IsControlDown)
|
||||
moveDelta *= 0.3f;
|
||||
|
||||
#if PLATFORM_SDL
|
||||
var mouseDelta = _mouseDelta;
|
||||
_mouseDelta = Float2.Zero;
|
||||
#else
|
||||
// Calculate smooth mouse delta not dependant on viewport size
|
||||
var offset = _viewMousePos - _startPos;
|
||||
if (_input.IsZooming && !_input.IsMouseRightDown && !_input.IsMouseLeftDown && !_input.IsMouseMiddleDown && !_isOrtho && !rmbWheel && !_isVirtualMouseRightDown)
|
||||
@@ -1700,18 +1722,21 @@ namespace FlaxEditor.Viewport
|
||||
mouseDelta += _mouseDeltaLast * _mouseAccelerationScale;
|
||||
_mouseDeltaLast = currentDelta;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Update
|
||||
moveDelta *= dt * (60.0f * 4.0f);
|
||||
mouseDelta *= 0.1833f * MouseSpeed * _mouseSensitivity;
|
||||
UpdateView(dt, ref moveDelta, ref mouseDelta, out var centerMouse);
|
||||
|
||||
#if !PLATFORM_SDL
|
||||
// Move mouse back to the root position
|
||||
if (centerMouse && (_input.IsMouseRightDown || _input.IsMouseLeftDown || _input.IsMouseMiddleDown || _isVirtualMouseRightDown))
|
||||
{
|
||||
var center = PointToWindow(_startPos);
|
||||
win.MousePosition = center;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Change Ortho size on mouse scroll
|
||||
if (_isOrtho && !rmbWheel)
|
||||
@@ -1723,6 +1748,8 @@ namespace FlaxEditor.Viewport
|
||||
}
|
||||
else
|
||||
{
|
||||
#if PLATFORM_SDL
|
||||
#else
|
||||
if (_input.IsMouseLeftDown || _input.IsMouseRightDown || _isVirtualMouseRightDown)
|
||||
{
|
||||
// Calculate smooth mouse delta not dependant on viewport size
|
||||
@@ -1737,6 +1764,7 @@ namespace FlaxEditor.Viewport
|
||||
_mouseDelta = Float2.Zero;
|
||||
}
|
||||
_mouseDeltaLast = Float2.Zero;
|
||||
#endif
|
||||
|
||||
if (ContainsFocus)
|
||||
{
|
||||
@@ -1786,6 +1814,12 @@ namespace FlaxEditor.Viewport
|
||||
_input.MouseWheelDelta = 0;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnMouseMoveRelative(ref Float2 mouseMotion)
|
||||
{
|
||||
_mouseDelta += mouseMotion;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool OnMouseDown(Float2 location, MouseButton button)
|
||||
{
|
||||
|
||||
@@ -351,6 +351,8 @@ namespace FlaxEditor.Viewport
|
||||
|
||||
private void OnCollectDrawCalls(ref RenderContext renderContext)
|
||||
{
|
||||
if (renderContext.View.Pass == DrawPass.Depth)
|
||||
return;
|
||||
DragHandlers.CollectDrawCalls(_debugDrawData, ref renderContext);
|
||||
if (ShowNavigation)
|
||||
Editor.Internal_DrawNavMesh();
|
||||
@@ -620,12 +622,12 @@ namespace FlaxEditor.Viewport
|
||||
|
||||
private static bool ValidateDragActorType(ScriptType actorType)
|
||||
{
|
||||
return Level.IsAnySceneLoaded;
|
||||
return Level.IsAnySceneLoaded && Editor.Instance.CodeEditing.Actors.Get().Contains(actorType);
|
||||
}
|
||||
|
||||
private static bool ValidateDragScriptItem(ScriptItem script)
|
||||
{
|
||||
return Editor.Instance.CodeEditing.Actors.Get(script) != ScriptType.Null;
|
||||
return Level.IsAnySceneLoaded && Editor.Instance.CodeEditing.Actors.Get(script) != ScriptType.Null;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user