@@ -14,84 +14,6 @@ use serde::{Deserialize, Serialize};
14
14
use super :: { click_text_edit:: ClickableTextEdit , value:: PlistValue } ;
15
15
use crate :: utils:: { ValueType , child_keys, pv_mut} ;
16
16
17
- #[ must_use]
18
- fn get_new_key ( keys : plist:: dictionary:: Keys , k : & str ) -> String {
19
- keys. filter ( |v| ( v. as_str ( ) == k) || ( v. starts_with ( k) && v. ends_with ( "Duplicate" ) ) )
20
- . last ( )
21
- . map_or_else ( || "New Child" . into ( ) , |v| format ! ( "{v} Duplicate" ) )
22
- }
23
-
24
- #[ must_use]
25
- pub fn render_menu ( resp : & Response , path : & [ String ] , p : & mut Value ) -> Option < bool > {
26
- let mut ret = None ;
27
-
28
- resp. context_menu ( |ui| {
29
- match ValueType :: from_val ( path, p) {
30
- ValueType :: Dictionary => {
31
- if ui. button ( "Add child" ) . clicked ( ) {
32
- let dict = pv_mut ( path, p) . as_dictionary_mut ( ) . unwrap ( ) ;
33
- dict. insert (
34
- get_new_key ( dict. keys ( ) , "New Child" ) ,
35
- Value :: String ( String :: new ( ) ) ,
36
- ) ;
37
- ui. close ( ) ;
38
- ret = Some ( false ) ;
39
- }
40
- if ui. button ( "Sort" ) . clicked ( ) {
41
- pv_mut ( path, p) . as_dictionary_mut ( ) . unwrap ( ) . sort_keys ( ) ;
42
- ui. close ( ) ;
43
- ret = Some ( false ) ;
44
- }
45
- }
46
- ValueType :: Array => {
47
- if ui. button ( "Add child" ) . clicked ( ) {
48
- pv_mut ( path, p)
49
- . as_array_mut ( )
50
- . unwrap ( )
51
- . push ( Value :: String ( String :: new ( ) ) ) ;
52
- ui. close ( ) ;
53
- ret = Some ( false ) ;
54
- }
55
- }
56
- _ => { }
57
- }
58
-
59
- let Some ( k) = path. last ( ) else {
60
- return ;
61
- } ;
62
-
63
- if ui. button ( "Duplicate" ) . clicked ( ) {
64
- match pv_mut ( & path[ ..path. len ( ) - 1 ] , p) {
65
- Value :: Dictionary ( v) => {
66
- v. insert ( get_new_key ( v. keys ( ) , k) , v. get ( k) . unwrap ( ) . clone ( ) ) ;
67
- }
68
- Value :: Array ( v) => {
69
- v. push ( v. get ( k. parse :: < usize > ( ) . unwrap ( ) ) . unwrap ( ) . clone ( ) ) ;
70
- }
71
- _ => unreachable ! ( ) ,
72
- }
73
- ui. close ( ) ;
74
- ret = Some ( false ) ;
75
- }
76
-
77
- if ui. button ( "Remove" ) . clicked ( ) {
78
- match pv_mut ( & path[ ..path. len ( ) - 1 ] , p) {
79
- Value :: Dictionary ( v) => {
80
- v. remove ( k) ;
81
- }
82
- Value :: Array ( v) => {
83
- v. remove ( k. parse :: < usize > ( ) . unwrap ( ) ) ;
84
- }
85
- _ => unreachable ! ( ) ,
86
- }
87
- ui. close ( ) ;
88
- ret = Some ( true ) ;
89
- }
90
- } ) ;
91
-
92
- ret
93
- }
94
-
95
17
#[ derive( Clone , Debug , Default , PartialEq , Serialize , Deserialize ) ]
96
18
struct State {
97
19
expanded : bool ,
@@ -121,13 +43,126 @@ pub struct PlistEntry {
121
43
id : Id ,
122
44
}
123
45
46
+ #[ derive( Clone , Copy , PartialEq , Eq , PartialOrd , Ord ) ]
47
+ pub enum ChangeState {
48
+ Unchanged ,
49
+ Changed ,
50
+ Removed ,
51
+ }
52
+
53
+ impl std:: ops:: BitOr for ChangeState {
54
+ type Output = Self ;
55
+
56
+ fn bitor ( self , rhs : Self ) -> Self :: Output {
57
+ self . max ( rhs)
58
+ }
59
+ }
60
+
61
+ impl std:: ops:: BitOrAssign for ChangeState {
62
+ fn bitor_assign ( & mut self , rhs : Self ) {
63
+ * self = * self | rhs
64
+ }
65
+ }
66
+
124
67
impl PlistEntry {
125
68
pub fn new ( data : Arc < Mutex < Value > > , path : Vec < String > ) -> Self {
126
69
let id = Id :: new ( & path) ;
127
70
Self { data, path, id }
128
71
}
129
72
130
- pub fn show ( self , body : & mut TableBody ) -> Option < bool > {
73
+ #[ must_use]
74
+ fn get_new_key ( keys : plist:: dictionary:: Keys , k : & str ) -> String {
75
+ keys. filter ( |v| ( v. as_str ( ) == k) || ( v. starts_with ( k) && v. ends_with ( "Duplicate" ) ) )
76
+ . last ( )
77
+ . map_or_else ( || "New Child" . into ( ) , |v| format ! ( "{v} Duplicate" ) )
78
+ }
79
+
80
+ #[ must_use]
81
+ fn render_menu ( resp : & Response , path : & [ String ] , p : & mut Value ) -> ChangeState {
82
+ let mut ret = ChangeState :: Unchanged ;
83
+
84
+ egui:: Popup :: context_menu ( resp) . show ( |ui| {
85
+ match ValueType :: from_val ( path, p) {
86
+ ValueType :: Dictionary => {
87
+ if ui. button ( "Add child" ) . clicked ( ) {
88
+ let dict = pv_mut ( path, p) . as_dictionary_mut ( ) . unwrap ( ) ;
89
+ dict. insert (
90
+ Self :: get_new_key ( dict. keys ( ) , "New Child" ) ,
91
+ Value :: String ( String :: new ( ) ) ,
92
+ ) ;
93
+ ui. close ( ) ;
94
+ ret |= ChangeState :: Changed ;
95
+ }
96
+ if ui. button ( "Sort" ) . clicked ( ) {
97
+ pv_mut ( path, p) . as_dictionary_mut ( ) . unwrap ( ) . sort_keys ( ) ;
98
+ ui. close ( ) ;
99
+ ret |= ChangeState :: Changed ;
100
+ }
101
+ }
102
+ ValueType :: Array => {
103
+ if ui. button ( "Add child" ) . clicked ( ) {
104
+ pv_mut ( path, p)
105
+ . as_array_mut ( )
106
+ . unwrap ( )
107
+ . push ( Value :: String ( String :: new ( ) ) ) ;
108
+ ui. close ( ) ;
109
+ ret |= ChangeState :: Changed ;
110
+ }
111
+ }
112
+ _ => { }
113
+ }
114
+
115
+ let Some ( k) = path. last ( ) else {
116
+ return ;
117
+ } ;
118
+
119
+ if ui. button ( "Duplicate" ) . clicked ( ) {
120
+ match pv_mut ( & path[ ..path. len ( ) - 1 ] , p) {
121
+ Value :: Dictionary ( v) => {
122
+ v. insert ( Self :: get_new_key ( v. keys ( ) , k) , v. get ( k) . unwrap ( ) . clone ( ) ) ;
123
+ }
124
+ Value :: Array ( v) => {
125
+ v. push ( v. get ( k. parse :: < usize > ( ) . unwrap ( ) ) . unwrap ( ) . clone ( ) ) ;
126
+ }
127
+ _ => unreachable ! ( ) ,
128
+ }
129
+ ui. close ( ) ;
130
+ ret |= ChangeState :: Changed ;
131
+ }
132
+
133
+ if ui. button ( "Remove" ) . clicked ( ) {
134
+ match pv_mut ( & path[ ..path. len ( ) - 1 ] , p) {
135
+ Value :: Dictionary ( v) => {
136
+ v. remove ( k) ;
137
+ }
138
+ Value :: Array ( v) => {
139
+ v. remove ( k. parse :: < usize > ( ) . unwrap ( ) ) ;
140
+ }
141
+ _ => unreachable ! ( ) ,
142
+ }
143
+ ui. close ( ) ;
144
+ ret |= ChangeState :: Removed ;
145
+ }
146
+ } ) ;
147
+
148
+ ret
149
+ }
150
+
151
+ fn show_immutable_key (
152
+ ui : & mut egui:: Ui ,
153
+ mut s : & str ,
154
+ path : & [ String ] ,
155
+ p : & mut Value ,
156
+ ) -> ChangeState {
157
+ let resp = ui. add (
158
+ TextEdit :: singleline ( & mut s)
159
+ . desired_width ( f32:: INFINITY )
160
+ . frame ( false ) ,
161
+ ) ;
162
+ Self :: render_menu ( & resp, path, p)
163
+ }
164
+
165
+ pub fn show ( self , body : & mut TableBody ) -> ChangeState {
131
166
let Self { data, mut path, id } = self ;
132
167
let mut state = State :: load ( body. ui_mut ( ) . ctx ( ) , id) . unwrap_or_default ( ) ;
133
168
let mut ty = ValueType :: from_val ( & path, & data. lock ( ) . unwrap ( ) ) ;
@@ -136,7 +171,7 @@ impl PlistEntry {
136
171
} else {
137
172
vec ! [ ]
138
173
} ;
139
- let mut ret = None ;
174
+ let mut ret = ChangeState :: Unchanged ;
140
175
body. row ( 20.0 , |mut row| {
141
176
let resp = row
142
177
. col ( |ui| {
@@ -164,60 +199,43 @@ impl PlistEntry {
164
199
& small_icon_response,
165
200
) ;
166
201
}
202
+ let mut data = data. lock ( ) . unwrap ( ) ;
167
203
if path. is_empty ( ) {
168
- let resp = ui. add (
169
- TextEdit :: singleline ( & mut "Root" )
170
- . desired_width ( f32:: INFINITY )
171
- . frame ( false ) ,
172
- ) ;
173
- let v = render_menu ( & resp, & path, & mut data. lock ( ) . unwrap ( ) ) ;
174
- ret = ret. map_or ( v, |vv| Some ( v. unwrap_or_default ( ) || vv) ) ;
204
+ ret |= Self :: show_immutable_key ( ui, "Root" , & path, & mut data) ;
175
205
return ;
176
206
}
177
207
let name = path. last ( ) . unwrap ( ) . clone ( ) ;
178
- let k = & name;
179
- let mut data = data. lock ( ) . unwrap ( ) ;
180
208
let Some ( dict) = pv_mut ( & path[ ..path. len ( ) - 1 ] , & mut data) . as_dictionary_mut ( )
181
209
else {
182
- let mut s = k. as_str ( ) ;
183
- let resp = ui. add (
184
- TextEdit :: singleline ( & mut s)
185
- . desired_width ( f32:: INFINITY )
186
- . frame ( false ) ,
187
- ) ;
188
- let v = render_menu ( & resp, & path, & mut data) ;
189
- ret = ret. map_or ( v, |vv| Some ( v. unwrap_or_default ( ) || vv) ) ;
210
+ ret |= Self :: show_immutable_key ( ui, name. as_str ( ) , & path, & mut data) ;
190
211
return ;
191
212
} ;
192
213
let dict_clone = dict. clone ( ) ;
193
214
let resp = ui. add ( ClickableTextEdit :: from_get_set (
194
215
|v| {
195
216
v. map_or_else (
196
- || k . clone ( ) ,
217
+ || name . clone ( ) ,
197
218
|val| {
198
219
if !dict. contains_key ( & val) {
199
- dict. insert ( val. clone ( ) , dict. get ( k ) . unwrap ( ) . clone ( ) ) ;
220
+ dict. insert ( val. clone ( ) , dict. get ( & name ) . unwrap ( ) . clone ( ) ) ;
200
221
path. last_mut ( ) . unwrap ( ) . clone_from ( & val) ;
201
- dict. remove ( k ) ;
222
+ dict. remove ( & name ) ;
202
223
}
203
224
val
204
225
} ,
205
226
)
206
227
} ,
207
- move |v| k == v || !dict_clone. contains_key ( v) ,
228
+ |v| name == v || !dict_clone. contains_key ( v) ,
208
229
false ,
209
230
) ) ;
210
231
ui. spacing_mut ( ) . item_spacing = prev_item_spacing;
211
- let v = render_menu ( & resp, & path, & mut data) ;
212
- drop ( data) ;
213
- ret = ret. map_or ( v, |vv| Some ( v. unwrap_or_default ( ) || vv) ) ;
232
+ ret |= Self :: render_menu ( & resp, & path, & mut data) ;
214
233
} )
215
234
. 1 ;
216
- if ret == Some ( true ) {
235
+ if ret == ChangeState :: Removed {
217
236
return ;
218
237
}
219
- let v = render_menu ( & resp, & path, & mut data. lock ( ) . unwrap ( ) ) ;
220
- ret = ret. map_or ( v, |vv| Some ( v. unwrap_or_default ( ) || vv) ) ;
238
+ ret |= Self :: render_menu ( & resp, & path, & mut data. lock ( ) . unwrap ( ) ) ;
221
239
row. col ( |ui| {
222
240
let prev_type = ty;
223
241
ComboBox :: from_id_salt ( id. with ( "type" ) )
@@ -236,25 +254,29 @@ impl PlistEntry {
236
254
if prev_type != ty {
237
255
let mut data = data. lock ( ) . unwrap ( ) ;
238
256
* pv_mut ( & path, & mut data) = match ty {
239
- ValueType :: Array => Value :: Array ( vec ! [ ] ) ,
240
- ValueType :: Dictionary => Value :: Dictionary ( plist:: Dictionary :: new ( ) ) ,
241
- ValueType :: Boolean => Value :: Boolean ( false ) ,
242
- ValueType :: Data => Value :: Data ( vec ! [ ] ) ,
243
- ValueType :: Date => Value :: Date ( plist:: Date :: from ( SystemTime :: now ( ) ) ) ,
244
- ValueType :: Real => Value :: Real ( 0.0 ) ,
245
- ValueType :: Integer => Value :: Integer ( plist:: Integer :: from ( 0 ) ) ,
246
- ValueType :: String => Value :: String ( String :: new ( ) ) ,
257
+ ValueType :: Array => Value :: Array ( Default :: default ( ) ) ,
258
+ ValueType :: Dictionary => Value :: Dictionary ( Default :: default ( ) ) ,
259
+ ValueType :: Boolean => Value :: Boolean ( Default :: default ( ) ) ,
260
+ ValueType :: Data => Value :: Data ( Default :: default ( ) ) ,
261
+ ValueType :: Date => Value :: Date ( SystemTime :: now ( ) . into ( ) ) ,
262
+ ValueType :: Real => Value :: Real ( Default :: default ( ) ) ,
263
+ ValueType :: Integer => Value :: Integer ( 0 . into ( ) ) ,
264
+ ValueType :: String => Value :: String ( Default :: default ( ) ) ,
265
+ } ;
266
+ ret |= if prev_type. is_expandable ( ) || ty. is_expandable ( ) {
267
+ ChangeState :: Removed
268
+ } else {
269
+ ChangeState :: Changed
247
270
} ;
248
- ret = Some ( prev_type. is_expandable ( ) || ty. is_expandable ( ) ) ;
249
271
}
250
272
} ) ;
251
- if ret == Some ( true ) {
273
+ if ret == ChangeState :: Removed {
252
274
return ;
253
275
}
254
276
row. col ( |ui| {
255
277
if !ty. is_expandable ( ) {
256
278
if PlistValue :: new ( & path, Arc :: clone ( & data) ) . show ( ui) {
257
- ret = ret . or ( Some ( false ) ) ;
279
+ ret |= ChangeState :: Changed ;
258
280
}
259
281
260
282
return ;
@@ -272,18 +294,17 @@ impl PlistEntry {
272
294
}
273
295
} ) ;
274
296
} ) ;
275
- if ret == Some ( true ) {
297
+ if ret == ChangeState :: Removed {
276
298
return ret;
277
299
}
278
300
if state. expanded {
279
301
for k in keys {
280
- let v = Self :: new (
302
+ ret | = Self :: new (
281
303
Arc :: clone ( & data) ,
282
304
path. iter ( ) . chain ( std:: iter:: once ( & k) ) . cloned ( ) . collect ( ) ,
283
305
)
284
306
. show ( body) ;
285
- ret = ret. map_or ( v, |vv| Some ( v. unwrap_or_default ( ) || vv) ) ;
286
- if v == Some ( true ) {
307
+ if ret == ChangeState :: Removed {
287
308
break ;
288
309
}
289
310
}
0 commit comments