]>
Commit | Line | Data |
---|---|---|
32368ac3 WB |
1 | use std::{cell::RefCell, marker::PhantomData, rc::Rc}; |
2 | ||
af0dfe0e | 3 | use cursive::{ |
ed191e60 | 4 | view::{Nameable, Resizable, ViewWrapper}, |
45082a3c CH |
5 | views::{ |
6 | Button, Dialog, DummyView, LinearLayout, NamedView, Panel, ScrollView, SelectView, TextView, | |
7 | }, | |
7393ed88 | 8 | Cursive, View, |
af0dfe0e | 9 | }; |
32368ac3 WB |
10 | |
11 | use super::{DiskSizeEditView, FormView, IntegerEditView}; | |
12 | use crate::options::{ | |
13 | AdvancedBootdiskOptions, BootdiskOptions, BtrfsBootdiskOptions, Disk, FsType, | |
14 | LvmBootdiskOptions, ZfsBootdiskOptions, FS_TYPES, ZFS_CHECKSUM_OPTIONS, ZFS_COMPRESS_OPTIONS, | |
15 | }; | |
6719eda6 | 16 | use crate::setup::ProxmoxProduct; |
af0dfe0e | 17 | |
ed191e60 | 18 | pub struct BootdiskOptionsView { |
af0dfe0e | 19 | view: LinearLayout, |
7393ed88 | 20 | advanced_options: Rc<RefCell<BootdiskOptions>>, |
ed191e60 CH |
21 | } |
22 | ||
23 | impl BootdiskOptionsView { | |
24 | pub fn new(disks: &[Disk], options: &BootdiskOptions) -> Self { | |
b977af78 CH |
25 | let bootdisk_form = FormView::new() |
26 | .child( | |
27 | "Target harddisk", | |
28 | SelectView::new() | |
29 | .popup() | |
30 | .with_all(disks.iter().map(|d| (d.to_string(), d.clone()))), | |
31 | ) | |
66baa275 | 32 | .with_name("bootdisk-options-target-disk"); |
ed191e60 | 33 | |
7393ed88 | 34 | let advanced_options = Rc::new(RefCell::new(options.clone())); |
ed191e60 CH |
35 | |
36 | let advanced_button = LinearLayout::horizontal() | |
37 | .child(DummyView.full_width()) | |
38 | .child(Button::new("Advanced options", { | |
7393ed88 | 39 | let disks = disks.to_owned(); |
ed191e60 CH |
40 | let options = advanced_options.clone(); |
41 | move |siv| { | |
7393ed88 | 42 | siv.add_layer(advanced_options_view(&disks, options.clone())); |
ed191e60 CH |
43 | } |
44 | })); | |
45 | ||
46 | let view = LinearLayout::vertical() | |
b977af78 | 47 | .child(bootdisk_form) |
ed191e60 CH |
48 | .child(DummyView) |
49 | .child(advanced_button); | |
50 | ||
51 | Self { | |
52 | view, | |
53 | advanced_options, | |
54 | } | |
55 | } | |
56 | ||
994c4ff0 | 57 | pub fn get_values(&mut self) -> Result<BootdiskOptions, String> { |
7393ed88 | 58 | let mut options = (*self.advanced_options).clone().into_inner(); |
ed191e60 | 59 | |
7393ed88 CH |
60 | if [FsType::Ext4, FsType::Xfs].contains(&options.fstype) { |
61 | let disk = self | |
62 | .view | |
994c4ff0 CH |
63 | .get_child_mut(0) |
64 | .and_then(|v| v.downcast_mut::<NamedView<FormView>>()) | |
65 | .map(NamedView::<FormView>::get_mut) | |
66 | .and_then(|v| v.get_value::<SelectView<Disk>, _>(0)) | |
67 | .ok_or("failed to retrieve filesystem type")?; | |
ed191e60 | 68 | |
7393ed88 CH |
69 | options.disks = vec![disk]; |
70 | } | |
71 | ||
994c4ff0 | 72 | Ok(options) |
ed191e60 | 73 | } |
af0dfe0e CH |
74 | } |
75 | ||
ed191e60 CH |
76 | impl ViewWrapper for BootdiskOptionsView { |
77 | cursive::wrap_impl!(self.view: LinearLayout); | |
78 | } | |
79 | ||
80 | struct AdvancedBootdiskOptionsView { | |
81 | view: LinearLayout, | |
82 | } | |
af0dfe0e | 83 | |
ed191e60 | 84 | impl AdvancedBootdiskOptionsView { |
7393ed88 | 85 | fn new(disks: &[Disk], options: &BootdiskOptions) -> Self { |
a96dc916 TL |
86 | let enable_btrfs = crate::setup_info().config.enable_btrfs; |
87 | ||
88 | let filter_btrfs = |fstype: &&FsType| -> bool { enable_btrfs || !fstype.is_btrfs() }; | |
89 | ||
66baa275 CH |
90 | let fstype_select = SelectView::new() |
91 | .popup() | |
a96dc916 TL |
92 | .with_all( |
93 | FS_TYPES | |
94 | .iter() | |
95 | .filter(filter_btrfs) | |
96 | .map(|t| (t.to_string(), *t)), | |
97 | ) | |
66baa275 CH |
98 | .selected( |
99 | FS_TYPES | |
100 | .iter() | |
a96dc916 | 101 | .filter(filter_btrfs) |
66baa275 CH |
102 | .position(|t| *t == options.fstype) |
103 | .unwrap_or_default(), | |
104 | ) | |
105 | .on_submit({ | |
106 | let disks = disks.to_owned(); | |
107 | move |siv, fstype| Self::fstype_on_submit(siv, &disks, fstype) | |
108 | }); | |
af0dfe0e | 109 | |
7393ed88 | 110 | let mut view = LinearLayout::vertical() |
ed191e60 | 111 | .child(DummyView.full_width()) |
66baa275 | 112 | .child(FormView::new().child("Filesystem", fstype_select)) |
7393ed88 CH |
113 | .child(DummyView.full_width()); |
114 | ||
115 | match &options.advanced { | |
116 | AdvancedBootdiskOptions::Lvm(lvm) => view.add_child(LvmBootdiskOptionsView::new(lvm)), | |
117 | AdvancedBootdiskOptions::Zfs(zfs) => { | |
118 | view.add_child(ZfsBootdiskOptionsView::new(disks, zfs)) | |
119 | } | |
56a304d5 CH |
120 | AdvancedBootdiskOptions::Btrfs(btrfs) => { |
121 | view.add_child(BtrfsBootdiskOptionsView::new(disks, btrfs)) | |
122 | } | |
7393ed88 | 123 | }; |
af0dfe0e CH |
124 | |
125 | Self { view } | |
126 | } | |
127 | ||
7393ed88 CH |
128 | fn fstype_on_submit(siv: &mut Cursive, disks: &[Disk], fstype: &FsType) { |
129 | siv.call_on_name("advanced-bootdisk-options-dialog", |view: &mut Dialog| { | |
130 | if let Some(AdvancedBootdiskOptionsView { view }) = | |
ce0b5865 | 131 | view.get_content_mut().downcast_mut() |
7393ed88 CH |
132 | { |
133 | view.remove_child(3); | |
134 | match fstype { | |
135 | FsType::Ext4 | FsType::Xfs => view.add_child(LvmBootdiskOptionsView::new( | |
136 | &LvmBootdiskOptions::defaults_from(&disks[0]), | |
137 | )), | |
138 | FsType::Zfs(_) => view.add_child(ZfsBootdiskOptionsView::new( | |
139 | disks, | |
cc655f8b | 140 | &ZfsBootdiskOptions::defaults_from(disks), |
7393ed88 | 141 | )), |
56a304d5 CH |
142 | FsType::Btrfs(_) => view.add_child(BtrfsBootdiskOptionsView::new( |
143 | disks, | |
cc655f8b | 144 | &BtrfsBootdiskOptions::defaults_from(disks), |
56a304d5 | 145 | )), |
7393ed88 CH |
146 | } |
147 | } | |
148 | }); | |
149 | ||
150 | siv.call_on_name( | |
151 | "bootdisk-options-target-disk", | |
66baa275 CH |
152 | |view: &mut FormView| match fstype { |
153 | FsType::Ext4 | FsType::Xfs => { | |
154 | view.replace_child( | |
155 | 0, | |
156 | SelectView::new() | |
157 | .popup() | |
158 | .with_all(disks.iter().map(|d| (d.to_string(), d.clone()))), | |
159 | ); | |
160 | } | |
161 | other => view.replace_child(0, TextView::new(other.to_string())), | |
7393ed88 CH |
162 | }, |
163 | ); | |
164 | } | |
165 | ||
166 | fn get_values(&mut self) -> Option<BootdiskOptions> { | |
ed191e60 CH |
167 | let fstype = self |
168 | .view | |
169 | .get_child(1)? | |
66baa275 CH |
170 | .downcast_ref::<FormView>()? |
171 | .get_value::<SelectView<FsType>, _>(0)?; | |
ed191e60 | 172 | |
7393ed88 CH |
173 | let advanced = self.view.get_child_mut(3)?; |
174 | ||
175 | if let Some(view) = advanced.downcast_mut::<LvmBootdiskOptionsView>() { | |
176 | Some(BootdiskOptions { | |
177 | disks: vec![], | |
178 | fstype, | |
179 | advanced: view.get_values().map(AdvancedBootdiskOptions::Lvm)?, | |
180 | }) | |
181 | } else if let Some(view) = advanced.downcast_mut::<ZfsBootdiskOptionsView>() { | |
182 | let (disks, advanced) = view.get_values()?; | |
ed191e60 | 183 | |
7393ed88 CH |
184 | Some(BootdiskOptions { |
185 | disks, | |
186 | fstype, | |
187 | advanced: AdvancedBootdiskOptions::Zfs(advanced), | |
188 | }) | |
56a304d5 CH |
189 | } else if let Some(view) = advanced.downcast_mut::<BtrfsBootdiskOptionsView>() { |
190 | let (disks, advanced) = view.get_values()?; | |
191 | ||
192 | Some(BootdiskOptions { | |
193 | disks, | |
194 | fstype, | |
195 | advanced: AdvancedBootdiskOptions::Btrfs(advanced), | |
196 | }) | |
7393ed88 CH |
197 | } else { |
198 | None | |
199 | } | |
af0dfe0e CH |
200 | } |
201 | } | |
202 | ||
ed191e60 | 203 | impl ViewWrapper for AdvancedBootdiskOptionsView { |
af0dfe0e CH |
204 | cursive::wrap_impl!(self.view: LinearLayout); |
205 | } | |
206 | ||
207 | struct LvmBootdiskOptionsView { | |
cd6d2d24 | 208 | view: FormView, |
af0dfe0e CH |
209 | } |
210 | ||
211 | impl LvmBootdiskOptionsView { | |
ed191e60 | 212 | fn new(options: &LvmBootdiskOptions) -> Self { |
6719eda6 | 213 | let is_pve = crate::setup_info().config.product == ProxmoxProduct::PVE; |
ed191e60 | 214 | // TODO: Set maximum accordingly to disk size |
cd6d2d24 CH |
215 | let view = FormView::new() |
216 | .child( | |
217 | "Total size", | |
859e3478 CH |
218 | DiskSizeEditView::new() |
219 | .content(options.total_size) | |
220 | .max_value(options.total_size), | |
cd6d2d24 | 221 | ) |
af0dfe0e | 222 | .child( |
cd6d2d24 | 223 | "Swap size", |
409fc0fd | 224 | DiskSizeEditView::new_emptyable().content_maybe(options.swap_size), |
af0dfe0e | 225 | ) |
6719eda6 TL |
226 | .child_conditional( |
227 | is_pve, | |
cd6d2d24 | 228 | "Maximum root volume size", |
409fc0fd | 229 | DiskSizeEditView::new_emptyable().content_maybe(options.max_root_size), |
af0dfe0e | 230 | ) |
6719eda6 TL |
231 | .child_conditional( |
232 | is_pve, | |
cd6d2d24 | 233 | "Maximum data volume size", |
409fc0fd | 234 | DiskSizeEditView::new_emptyable().content_maybe(options.max_data_size), |
cd6d2d24 CH |
235 | ) |
236 | .child( | |
237 | "Minimum free LVM space", | |
409fc0fd | 238 | DiskSizeEditView::new_emptyable().content_maybe(options.min_lvm_free), |
af0dfe0e CH |
239 | ); |
240 | ||
241 | Self { view } | |
242 | } | |
243 | ||
244 | fn get_values(&mut self) -> Option<LvmBootdiskOptions> { | |
6719eda6 TL |
245 | let is_pve = crate::setup_info().config.product == ProxmoxProduct::PVE; |
246 | let min_lvm_free_id = if is_pve { 4 } else { 2 }; | |
247 | let max_root_size = if is_pve { | |
248 | self.view.get_value::<DiskSizeEditView, _>(2) | |
249 | } else { | |
250 | None | |
251 | }; | |
252 | let max_data_size = if is_pve { | |
253 | self.view.get_value::<DiskSizeEditView, _>(3) | |
254 | } else { | |
255 | None | |
256 | }; | |
af0dfe0e | 257 | Some(LvmBootdiskOptions { |
cd6d2d24 | 258 | total_size: self.view.get_value::<DiskSizeEditView, _>(0)?, |
409fc0fd | 259 | swap_size: self.view.get_value::<DiskSizeEditView, _>(1), |
6719eda6 TL |
260 | max_root_size, |
261 | max_data_size, | |
262 | min_lvm_free: self.view.get_value::<DiskSizeEditView, _>(min_lvm_free_id), | |
af0dfe0e CH |
263 | }) |
264 | } | |
265 | } | |
266 | ||
267 | impl ViewWrapper for LvmBootdiskOptionsView { | |
cd6d2d24 | 268 | cursive::wrap_impl!(self.view: FormView); |
af0dfe0e | 269 | } |
ed191e60 | 270 | |
ee1437bb | 271 | struct MultiDiskOptionsView<T> { |
56a304d5 | 272 | view: LinearLayout, |
ee1437bb | 273 | phantom: PhantomData<T>, |
56a304d5 CH |
274 | } |
275 | ||
ee1437bb | 276 | impl<T: View> MultiDiskOptionsView<T> { |
9e5cf6b6 | 277 | fn new(avail_disks: &[Disk], selected_disks: &[usize], options_view: T) -> Self { |
429718b8 CH |
278 | let mut selectable_disks = avail_disks |
279 | .iter() | |
280 | .map(|d| (d.to_string(), Some(d.clone()))) | |
281 | .collect::<Vec<(String, Option<Disk>)>>(); | |
282 | ||
283 | selectable_disks.push(("-- do not use --".to_owned(), None)); | |
284 | ||
d36c96af | 285 | let mut disk_form = FormView::new(); |
9e5cf6b6 | 286 | for (i, _) in avail_disks.iter().enumerate() { |
d36c96af | 287 | disk_form.add_child( |
56a304d5 CH |
288 | &format!("Harddisk {i}"), |
289 | SelectView::new() | |
290 | .popup() | |
429718b8 | 291 | .with_all(selectable_disks.clone()) |
cc655f8b | 292 | .selected(selected_disks[i]), |
d36c96af | 293 | ); |
56a304d5 CH |
294 | } |
295 | ||
d36c96af | 296 | let disk_select_view = LinearLayout::vertical() |
cdba54ce | 297 | .child(TextView::new("Disk setup").center()) |
d36c96af | 298 | .child(DummyView) |
45082a3c | 299 | .child(ScrollView::new(disk_form)); |
d36c96af | 300 | |
56a304d5 | 301 | let options_view = LinearLayout::vertical() |
cdba54ce | 302 | .child(TextView::new("Advanced options").center()) |
56a304d5 | 303 | .child(DummyView) |
ee1437bb | 304 | .child(options_view); |
56a304d5 CH |
305 | |
306 | let view = LinearLayout::horizontal() | |
307 | .child(disk_select_view) | |
308 | .child(DummyView.fixed_width(3)) | |
309 | .child(options_view); | |
310 | ||
ee1437bb | 311 | Self { |
82cc9fc4 | 312 | view: LinearLayout::vertical().child(view), |
ee1437bb CH |
313 | phantom: PhantomData, |
314 | } | |
56a304d5 CH |
315 | } |
316 | ||
7f273738 | 317 | fn top_panel(mut self, view: impl View) -> Self { |
82cc9fc4 CH |
318 | if self.has_top_panel() { |
319 | self.view.remove_child(0); | |
320 | } | |
7f273738 | 321 | |
82cc9fc4 | 322 | self.view.insert_child(0, Panel::new(view)); |
7f273738 CH |
323 | self |
324 | } | |
325 | ||
cc655f8b SS |
326 | /// |
327 | /// This function returns a tuple of vectors. The first vector contains the currently selected | |
328 | /// disks in order of their selection slot. Empty slots are filtered out. The second vector | |
329 | /// contains indices of each slot's selection, which enables us to restore the selection even | |
330 | /// for empty slots. | |
331 | /// | |
332 | fn get_disks_and_selection(&mut self) -> Option<(Vec<Disk>, Vec<usize>)> { | |
56a304d5 | 333 | let mut disks = vec![]; |
82cc9fc4 CH |
334 | let view_top_index = usize::from(self.has_top_panel()); |
335 | ||
d36c96af CH |
336 | let disk_form = self |
337 | .view | |
82cc9fc4 CH |
338 | .get_child(view_top_index)? |
339 | .downcast_ref::<LinearLayout>()? | |
d36c96af CH |
340 | .get_child(0)? |
341 | .downcast_ref::<LinearLayout>()? | |
342 | .get_child(2)? | |
45082a3c CH |
343 | .downcast_ref::<ScrollView<FormView>>()? |
344 | .get_inner(); | |
56a304d5 | 345 | |
cc655f8b SS |
346 | let mut selected_disks = Vec::new(); |
347 | ||
d36c96af | 348 | for i in 0..disk_form.len() { |
429718b8 | 349 | let disk = disk_form.get_value::<SelectView<Option<Disk>>, _>(i)?; |
56a304d5 | 350 | |
429718b8 CH |
351 | // `None` means no disk was selected for this slot |
352 | if let Some(disk) = disk { | |
353 | disks.push(disk); | |
354 | } | |
cc655f8b SS |
355 | |
356 | selected_disks.push( | |
357 | disk_form | |
358 | .get_child::<SelectView<Option<Disk>>>(i)? | |
359 | .selected_id()?, | |
360 | ); | |
56a304d5 CH |
361 | } |
362 | ||
cc655f8b | 363 | Some((disks, selected_disks)) |
ee1437bb | 364 | } |
56a304d5 | 365 | |
ee1437bb | 366 | fn inner_mut(&mut self) -> Option<&mut T> { |
82cc9fc4 CH |
367 | let view_top_index = usize::from(self.has_top_panel()); |
368 | ||
ee1437bb | 369 | self.view |
82cc9fc4 CH |
370 | .get_child_mut(view_top_index)? |
371 | .downcast_mut::<LinearLayout>()? | |
56a304d5 | 372 | .get_child_mut(2)? |
ee1437bb CH |
373 | .downcast_mut::<LinearLayout>()? |
374 | .get_child_mut(2)? | |
375 | .downcast_mut::<T>() | |
376 | } | |
82cc9fc4 CH |
377 | |
378 | fn has_top_panel(&self) -> bool { | |
379 | // The root view should only ever have one or two children | |
380 | assert!([1, 2].contains(&self.view.len())); | |
381 | ||
382 | self.view.len() == 2 | |
383 | } | |
ee1437bb CH |
384 | } |
385 | ||
386 | impl<T: 'static> ViewWrapper for MultiDiskOptionsView<T> { | |
387 | cursive::wrap_impl!(self.view: LinearLayout); | |
388 | } | |
389 | ||
390 | struct BtrfsBootdiskOptionsView { | |
d36c96af | 391 | view: MultiDiskOptionsView<FormView>, |
ee1437bb CH |
392 | } |
393 | ||
394 | impl BtrfsBootdiskOptionsView { | |
ee1437bb CH |
395 | fn new(disks: &[Disk], options: &BtrfsBootdiskOptions) -> Self { |
396 | let view = MultiDiskOptionsView::new( | |
397 | disks, | |
cc655f8b | 398 | &options.selected_disks, |
d36c96af | 399 | FormView::new().child("hdsize", DiskSizeEditView::new().content(options.disk_size)), |
7f273738 CH |
400 | ) |
401 | .top_panel(TextView::new("Btrfs integration is a technology preview!").center()); | |
ee1437bb CH |
402 | |
403 | Self { view } | |
404 | } | |
405 | ||
406 | fn get_values(&mut self) -> Option<(Vec<Disk>, BtrfsBootdiskOptions)> { | |
cc655f8b | 407 | let (disks, selected_disks) = self.view.get_disks_and_selection()?; |
d36c96af | 408 | let disk_size = self.view.inner_mut()?.get_value::<DiskSizeEditView, _>(0)?; |
56a304d5 | 409 | |
cc655f8b SS |
410 | Some(( |
411 | disks, | |
412 | BtrfsBootdiskOptions { | |
413 | disk_size, | |
414 | selected_disks, | |
415 | }, | |
416 | )) | |
56a304d5 CH |
417 | } |
418 | } | |
419 | ||
420 | impl ViewWrapper for BtrfsBootdiskOptionsView { | |
d36c96af | 421 | cursive::wrap_impl!(self.view: MultiDiskOptionsView<FormView>); |
56a304d5 CH |
422 | } |
423 | ||
7393ed88 | 424 | struct ZfsBootdiskOptionsView { |
d36c96af | 425 | view: MultiDiskOptionsView<FormView>, |
7393ed88 CH |
426 | } |
427 | ||
428 | impl ZfsBootdiskOptionsView { | |
429 | // TODO: Re-apply previous disk selection from `options` correctly | |
430 | fn new(disks: &[Disk], options: &ZfsBootdiskOptions) -> Self { | |
d36c96af CH |
431 | let inner = FormView::new() |
432 | .child("ashift", IntegerEditView::new().content(options.ashift)) | |
433 | .child( | |
7393ed88 CH |
434 | "compress", |
435 | SelectView::new() | |
436 | .popup() | |
437 | .with_all(ZFS_COMPRESS_OPTIONS.iter().map(|o| (o.to_string(), *o))) | |
438 | .selected( | |
439 | ZFS_COMPRESS_OPTIONS | |
440 | .iter() | |
441 | .position(|o| *o == options.compress) | |
442 | .unwrap_or_default(), | |
443 | ), | |
d36c96af CH |
444 | ) |
445 | .child( | |
7393ed88 CH |
446 | "checksum", |
447 | SelectView::new() | |
448 | .popup() | |
449 | .with_all(ZFS_CHECKSUM_OPTIONS.iter().map(|o| (o.to_string(), *o))) | |
450 | .selected( | |
451 | ZFS_CHECKSUM_OPTIONS | |
452 | .iter() | |
453 | .position(|o| *o == options.checksum) | |
454 | .unwrap_or_default(), | |
455 | ), | |
d36c96af CH |
456 | ) |
457 | .child("copies", IntegerEditView::new().content(options.copies)) | |
458 | .child("hdsize", DiskSizeEditView::new().content(options.disk_size)); | |
7393ed88 | 459 | |
cc655f8b | 460 | let view = MultiDiskOptionsView::new(disks, &options.selected_disks, inner) |
7f273738 CH |
461 | .top_panel(TextView::new( |
462 | "ZFS is not compatible with hardware RAID controllers, for details see the documentation." | |
463 | ).center()); | |
464 | ||
465 | Self { view } | |
7393ed88 CH |
466 | } |
467 | ||
468 | fn get_values(&mut self) -> Option<(Vec<Disk>, ZfsBootdiskOptions)> { | |
cc655f8b | 469 | let (disks, selected_disks) = self.view.get_disks_and_selection()?; |
d36c96af | 470 | let view = self.view.inner_mut()?; |
7393ed88 | 471 | |
d36c96af CH |
472 | let ashift = view.get_value::<IntegerEditView, _>(0)?; |
473 | let compress = view.get_value::<SelectView<_>, _>(1)?; | |
474 | let checksum = view.get_value::<SelectView<_>, _>(2)?; | |
475 | let copies = view.get_value::<IntegerEditView, _>(3)?; | |
476 | let disk_size = view.get_value::<DiskSizeEditView, _>(4)?; | |
7393ed88 CH |
477 | |
478 | Some(( | |
479 | disks, | |
480 | ZfsBootdiskOptions { | |
481 | ashift, | |
482 | compress, | |
483 | checksum, | |
484 | copies, | |
485 | disk_size, | |
cc655f8b | 486 | selected_disks, |
7393ed88 CH |
487 | }, |
488 | )) | |
489 | } | |
490 | } | |
491 | ||
492 | impl ViewWrapper for ZfsBootdiskOptionsView { | |
d36c96af | 493 | cursive::wrap_impl!(self.view: MultiDiskOptionsView<FormView>); |
7393ed88 CH |
494 | } |
495 | ||
496 | fn advanced_options_view(disks: &[Disk], options: Rc<RefCell<BootdiskOptions>>) -> impl View { | |
497 | Dialog::around(AdvancedBootdiskOptionsView::new( | |
498 | disks, | |
499 | &(*options).borrow(), | |
500 | )) | |
501 | .title("Advanced bootdisk options") | |
502 | .button("Ok", { | |
503 | let options_ref = options.clone(); | |
504 | move |siv| { | |
505 | let options = siv | |
506 | .call_on_name("advanced-bootdisk-options-dialog", |view: &mut Dialog| { | |
507 | view.get_content_mut() | |
ce0b5865 | 508 | .downcast_mut() |
7393ed88 CH |
509 | .and_then(AdvancedBootdiskOptionsView::get_values) |
510 | }) | |
511 | .flatten(); | |
512 | ||
5ed7f495 TL |
513 | if let Some(disks) = options.as_ref().map(|opts| &opts.disks) { |
514 | if disks.len() > 1 { | |
515 | for i in 0..(disks.len() - 1) { | |
516 | let check_disk = &disks[i]; | |
517 | for disk in &disks[(i + 1)..] { | |
518 | if disk.index == check_disk.index { | |
519 | siv.add_layer(Dialog::info(format!( | |
520 | "cannot select same disk ({}) twice", | |
521 | disk.path | |
522 | ))); | |
523 | return; | |
524 | } | |
525 | } | |
526 | } | |
527 | } | |
528 | } | |
529 | ||
7393ed88 CH |
530 | siv.pop_layer(); |
531 | if let Some(options) = options { | |
532 | *(*options_ref).borrow_mut() = options; | |
ed191e60 | 533 | } |
7393ed88 CH |
534 | } |
535 | }) | |
536 | .with_name("advanced-bootdisk-options-dialog") | |
fccf6bb0 | 537 | .max_size((120, 40)) |
ed191e60 | 538 | } |