@@ -9,6 +9,7 @@ use bevy::{
9
9
scene2:: { CommandsSpawnScene , Scene , SceneList , bsn} ,
10
10
} ;
11
11
use bevy_editor_core:: { prelude:: * , selection:: common_conditions:: primary_selection_changed} ;
12
+ use bevy_editor_styles:: Theme ;
12
13
use bevy_pane_layout:: prelude:: * ;
13
14
14
15
/// Plugin for the editor properties pane.
@@ -18,9 +19,9 @@ impl Plugin for PropertiesPanePlugin {
18
19
fn build ( & self , app : & mut App ) {
19
20
app. register_pane ( "Properties" , setup_pane) . add_systems (
20
21
Update ,
21
- update_properties_pane. run_if (
22
+ ( update_properties_pane. run_if (
22
23
primary_selection_changed. or ( any_match_filter :: < Added < PropertiesPaneBody > > ) ,
23
- ) ,
24
+ ) , ) ,
24
25
) ;
25
26
}
26
27
}
@@ -49,31 +50,46 @@ fn setup_pane(pane: In<PaneStructure>, mut commands: Commands) {
49
50
fn update_properties_pane (
50
51
pane_bodies : Query < Entity , With < PropertiesPaneBody > > ,
51
52
selection : Res < EditorSelection > ,
53
+ theme : Res < Theme > ,
52
54
world : & World ,
53
55
mut commands : Commands ,
54
56
) {
55
57
for pane_body in & pane_bodies {
56
58
commands. entity ( pane_body) . despawn_children ( ) ;
57
59
commands
58
- . spawn_scene ( properties_pane ( & selection, world) )
60
+ . spawn_scene ( properties_pane ( & selection, & theme , world) )
59
61
. insert ( ChildOf ( pane_body) ) ;
60
62
}
61
63
}
62
64
63
- fn properties_pane ( selection : & EditorSelection , world : & World ) -> impl Scene {
65
+ fn properties_pane ( selection : & EditorSelection , theme : & Theme , world : & World ) -> impl Scene {
64
66
match selection. primary ( ) {
65
- Some ( selection) => bsn ! { Node { flex_direction: FlexDirection :: Column } [
66
- { component_list( selection, world) }
67
+ Some ( selection) => bsn ! {
68
+ Node {
69
+ flex_direction: FlexDirection :: Column ,
70
+ padding: UiRect :: all( Val :: Px ( 8.0 ) ) ,
71
+ row_gap: Val :: Px ( 6.0 )
72
+ } [
73
+ { component_list( selection, theme, world) }
67
74
] }
68
75
. boxed_scene ( ) ,
69
76
None => bsn ! {
70
- ( Text ( "Select an entity to inspect" ) ThemedText )
77
+ Node {
78
+ flex_direction: FlexDirection :: Column ,
79
+ justify_content: JustifyContent :: Center ,
80
+ align_items: AlignItems :: Center ,
81
+ padding: UiRect :: all( Val :: Px ( 24.0 ) )
82
+ } [
83
+ Text ( "Select an entity to inspect" )
84
+ TextFont :: from_font_size( 14.0 )
85
+ TextColor ( Color :: srgb( 0.514 , 0.514 , 0.522 ) ) ,
86
+ ]
71
87
}
72
88
. boxed_scene ( ) ,
73
89
}
74
90
}
75
91
76
- fn component_list ( entity : Entity , world : & World ) -> impl SceneList {
92
+ fn component_list ( entity : Entity , theme : & Theme , world : & World ) -> impl SceneList {
77
93
let type_registry = world. resource :: < AppTypeRegistry > ( ) . read ( ) ;
78
94
world
79
95
. inspect_entity ( entity)
@@ -98,72 +114,116 @@ fn component_list(entity: Entity, world: &World) -> impl SceneList {
98
114
bsn ! {
99
115
Node {
100
116
flex_direction: FlexDirection :: Column ,
101
- margin: UiRect :: all( Val :: Px ( 4.0 ) ) ,
102
- } [
117
+ margin: UiRect :: bottom( Val :: Px ( 6.0 ) ) ,
118
+ border: UiRect :: all( Val :: Px ( 1.0 ) ) ,
119
+ padding: UiRect :: all( Val :: Px ( 0.0 ) )
120
+ }
121
+ // CSS: #2A2A2E - Component background
122
+ BackgroundColor ( Color :: srgb( 0.165 , 0.165 , 0.180 ) )
123
+ // CSS: #414142 - Border color
124
+ BorderColor :: all( Color :: srgb( 0.255 , 0.255 , 0.259 ) )
125
+ BorderRadius :: all( Val :: Px ( 5.0 ) )
126
+ [
127
+ // Component header - CSS styling
103
128
Node {
104
129
flex_direction: FlexDirection :: Row ,
130
+ justify_content: JustifyContent :: SpaceBetween ,
105
131
align_items: AlignItems :: Center ,
106
- } [
107
- TextFont :: from_font_size( 14.0 )
108
- Text ( { format!( "{name}" ) } )
109
- TextColor ( Color :: WHITE )
132
+ padding: UiRect :: all( Val :: Px ( 8.0 ) ) ,
133
+ height: Val :: Px ( 26.0 )
134
+ }
135
+ // CSS: #36373B - Header background
136
+ BackgroundColor ( Color :: srgb( 0.212 , 0.216 , 0.231 ) )
137
+ BorderRadius :: top( Val :: Px ( 5.0 ) )
138
+ [
139
+ Node {
140
+ flex_direction: FlexDirection :: Row ,
141
+ align_items: AlignItems :: Center ,
142
+ column_gap: Val :: Px ( 5.0 )
143
+ } [
144
+ Text ( "▼" )
145
+ TextFont :: from_font_size( 12.0 )
146
+ // CSS: #C4C4C4 - Chevron color
147
+ TextColor ( Color :: srgb( 0.769 , 0.769 , 0.769 ) ) ,
148
+
149
+ Text ( { format!( "{name}" ) } )
150
+ TextFont :: from_font_size( 12.0 )
151
+ // CSS: #DCDCDC - Component name
152
+ TextColor ( Color :: srgb( 0.863 , 0.863 , 0.863 ) ) ,
153
+ ] ,
154
+
155
+ Text ( "⋯" )
156
+ TextFont :: from_font_size( 12.0 )
157
+ // CSS: #C4C4C4 - Menu dots
158
+ TextColor ( Color :: srgb( 0.769 , 0.769 , 0.769 ) ) ,
110
159
] ,
111
160
// Component fields
112
161
( { match reflect {
113
- Some ( reflect) => component( type_info, reflect) . boxed_scene( ) ,
162
+ Some ( reflect) => component( type_info, reflect, theme ) . boxed_scene( ) ,
114
163
None => bsn! {
115
164
Node {
116
165
flex_direction: FlexDirection :: Row ,
166
+ padding: UiRect :: all( Val :: Px ( 8.0 ) )
117
167
} [
118
- Text ( "<unavailable>" )
119
- TextFont :: from_font_size( 10 .0)
120
- TextColor ( Color :: srgb( 1.0 , 0.0 , 0.0 ) )
168
+ Text ( "<reflection unavailable>" )
169
+ TextFont :: from_font_size( 11 .0)
170
+ TextColor ( Color :: srgb( 0.514 , 0.514 , 0.522 ) ) ,
121
171
]
122
172
} . boxed_scene( ) ,
123
- } } )
173
+ } } ) ,
124
174
]
125
175
}
126
176
} )
127
177
. collect :: < Vec < _ > > ( )
128
178
}
129
179
130
- fn component ( type_info : Option < & TypeInfo > , reflect : & dyn Reflect ) -> impl Scene {
180
+ fn component ( type_info : Option < & TypeInfo > , reflect : & dyn Reflect , theme : & Theme ) -> impl Scene {
131
181
match type_info {
132
- Some ( TypeInfo :: Struct ( info) ) => reflected_struct ( info, reflect) . boxed_scene ( ) ,
133
- Some ( TypeInfo :: TupleStruct ( info) ) => reflected_tuple_struct ( info) . boxed_scene ( ) ,
134
- Some ( TypeInfo :: Enum ( info) ) => reflected_enum ( info) . boxed_scene ( ) ,
182
+ Some ( TypeInfo :: Struct ( info) ) => reflected_struct ( info, reflect, theme ) . boxed_scene ( ) ,
183
+ Some ( TypeInfo :: TupleStruct ( info) ) => reflected_tuple_struct ( info, theme ) . boxed_scene ( ) ,
184
+ Some ( TypeInfo :: Enum ( info) ) => reflected_enum ( info, theme ) . boxed_scene ( ) ,
135
185
_ => bsn ! { } . boxed_scene ( ) ,
136
186
}
137
187
}
138
- fn reflected_struct ( struct_info : & StructInfo , reflect : & dyn Reflect ) -> impl Scene {
188
+ fn reflected_struct ( struct_info : & StructInfo , reflect : & dyn Reflect , _theme : & Theme ) -> impl Scene {
139
189
let fields = struct_info
140
190
. iter ( )
141
191
. enumerate ( )
142
192
. map ( |( i, field) | {
143
- let valuee = reflect
193
+ let field_reflect = reflect
144
194
. reflect_ref ( )
145
195
. as_struct ( )
146
- . map ( |s| s. field_at ( i) )
147
- . map ( |v| format ! ( "{v:?}" ) )
148
- . unwrap_or ( "<unavailable>" . to_string ( ) ) ;
196
+ . ok ( )
197
+ . and_then ( |s| s. field_at ( i) ) ;
149
198
150
199
let field_name = field. name ( ) ;
200
+
201
+ let value_string = field_reflect
202
+ . map ( |v| format ! ( "{v:?}" ) )
203
+ . unwrap_or_else ( || "<unavailable>" . to_string ( ) ) ;
204
+
151
205
bsn ! {
152
206
Node {
153
207
flex_direction: FlexDirection :: Row ,
154
208
margin: UiRect :: vertical( Val :: Px ( 2.0 ) ) ,
155
- } [
156
- (
157
- Text ( field_name)
158
- TextFont :: from_font_size( 12.0 )
159
- TextColor ( Color :: srgb( 0.8 , 0.8 , 0.8 ) )
160
- ) ,
161
- (
162
- // Value (use reflection to get value as string)
163
- Text ( { valuee. clone( ) } )
164
- TextFont :: from_font_size( 10.0 )
165
- TextColor ( Color :: WHITE )
166
- ) ,
209
+ padding: UiRect :: all( Val :: Px ( 5.0 ) ) ,
210
+ justify_content: JustifyContent :: SpaceBetween ,
211
+ align_items: AlignItems :: Center ,
212
+ min_height: Val :: Px ( 22.0 )
213
+ }
214
+ // CSS: #36373B - Field background
215
+ BackgroundColor ( Color :: srgb( 0.212 , 0.216 , 0.231 ) )
216
+ BorderRadius :: all( Val :: Px ( 3.0 ) )
217
+ [
218
+ Text ( field_name)
219
+ TextFont :: from_font_size( 12.0 )
220
+ // CSS: #DADADA - Field labels
221
+ TextColor ( Color :: srgb( 0.855 , 0.855 , 0.855 ) ) ,
222
+
223
+ Text ( { value_string. clone( ) } )
224
+ TextFont :: from_font_size( 12.0 )
225
+ // CSS: #C2C2C2 - Field values
226
+ TextColor ( Color :: srgb( 0.761 , 0.761 , 0.761 ) ) ,
167
227
]
168
228
}
169
229
} )
@@ -172,11 +232,13 @@ fn reflected_struct(struct_info: &StructInfo, reflect: &dyn Reflect) -> impl Sce
172
232
bsn ! {
173
233
Node {
174
234
flex_direction: FlexDirection :: Column ,
235
+ padding: UiRect :: all( Val :: Px ( 7.0 ) ) ,
236
+ row_gap: Val :: Px ( 4.0 )
175
237
} [ { fields} ]
176
238
}
177
239
}
178
240
179
- fn reflected_tuple_struct ( tuple_struct_info : & TupleStructInfo ) -> impl Scene {
241
+ fn reflected_tuple_struct ( tuple_struct_info : & TupleStructInfo , _theme : & Theme ) -> impl Scene {
180
242
let fields = tuple_struct_info
181
243
. iter ( )
182
244
. map ( |_field| {
@@ -189,12 +251,12 @@ fn reflected_tuple_struct(tuple_struct_info: &TupleStructInfo) -> impl Scene {
189
251
190
252
bsn ! {
191
253
Node {
192
- flex_direction: FlexDirection :: Column ,
254
+ flex_direction: FlexDirection :: Column
193
255
} [ { fields} ]
194
256
}
195
257
}
196
258
197
- fn reflected_enum ( enum_info : & EnumInfo ) -> impl Scene {
259
+ fn reflected_enum ( enum_info : & EnumInfo , _theme : & Theme ) -> impl Scene {
198
260
let variants = enum_info
199
261
. iter ( )
200
262
. map ( |variant| {
0 commit comments