desktop: Made OptionalUrlField an OptionalField<UrlField>

This commit is contained in:
Nathan Adams 2024-04-24 00:22:36 +02:00
parent 9d6d945ca4
commit 34c994a28f
1 changed files with 76 additions and 31 deletions

View File

@ -19,9 +19,9 @@ pub struct OpenDialog {
// These are outside of PlayerOptions as it can be an invalid value (ie URL) during typing, // These are outside of PlayerOptions as it can be an invalid value (ie URL) during typing,
// and we don't want to clear the value if the user, ie, toggles the checkbox. // and we don't want to clear the value if the user, ie, toggles the checkbox.
spoof_url: OptionalUrlField, spoof_url: OptionalField<UrlField>,
base_url: OptionalUrlField, base_url: OptionalField<UrlField>,
proxy_url: OptionalUrlField, proxy_url: OptionalField<UrlField>,
path: PathOrUrlField, path: PathOrUrlField,
framerate: f64, framerate: f64,
@ -34,9 +34,18 @@ impl OpenDialog {
default_url: Option<Url>, default_url: Option<Url>,
event_loop: EventLoopProxy<RuffleEvent>, event_loop: EventLoopProxy<RuffleEvent>,
) -> Self { ) -> Self {
let spoof_url = OptionalUrlField::new(&defaults.spoof_url, "https://example.org/game.swf"); let spoof_url = OptionalField::new(
let base_url = OptionalUrlField::new(&defaults.base, "https://example.org"); defaults.spoof_url.as_ref().map(Url::to_string),
let proxy_url = OptionalUrlField::new(&defaults.proxy, "socks5://localhost:8080"); UrlField::new("https://example.org/game.swf"),
);
let base_url = OptionalField::new(
defaults.base.as_ref().map(Url::to_string),
UrlField::new("https://example.org"),
);
let proxy_url = OptionalField::new(
defaults.proxy.as_ref().map(Url::to_string),
UrlField::new("socks5://localhost:8080"),
);
let path = PathOrUrlField::new(default_url, "path/to/movie.swf"); let path = PathOrUrlField::new(default_url, "path/to/movie.swf");
Self { Self {
options: defaults, options: defaults,
@ -517,56 +526,92 @@ impl OpenDialog {
} }
} }
struct OptionalUrlField { trait InnerField {
value: String, type Value;
error: bool, type Result;
enabled: bool,
fn value_if_missing(&self) -> Self::Value;
fn widget<'a>(&self, ui: &Ui, value: &'a mut Self::Value, error: bool) -> impl Widget + 'a;
fn value_to_result(&self, value: &Self::Value) -> Result<Self::Result, ()>;
}
struct UrlField {
hint: &'static str, hint: &'static str,
} }
impl OptionalUrlField { impl UrlField {
pub fn new(default: &Option<Url>, hint: &'static str) -> Self { pub fn new(hint: &'static str) -> Self {
Self { hint }
}
}
impl InnerField for UrlField {
type Value = String;
type Result = Url;
fn value_if_missing(&self) -> Self::Value {
String::new()
}
fn widget<'a>(&self, ui: &Ui, value: &'a mut Self::Value, error: bool) -> impl Widget + 'a {
TextEdit::singleline(value)
.hint_text(self.hint)
.text_color_opt(if error {
Some(ui.style().visuals.error_fg_color)
} else {
None
})
}
fn value_to_result(&self, value: &Self::Value) -> Result<Self::Result, ()> {
Url::parse(value).map_err(|_| ())
}
}
struct OptionalField<Inner: InnerField> {
value: Inner::Value,
error: bool,
enabled: bool,
inner: Inner,
}
impl<Inner: InnerField> OptionalField<Inner> {
pub fn new(default: Option<Inner::Value>, inner: Inner) -> Self {
if let Some(default) = default { if let Some(default) = default {
Self { Self {
value: default.to_string(), value: default,
error: false, error: false,
enabled: true, enabled: true,
hint, inner,
} }
} else { } else {
Self { Self {
value: "".to_string(), value: inner.value_if_missing(),
error: false, error: false,
enabled: false, enabled: false,
hint, inner,
} }
} }
} }
pub fn ui(&mut self, ui: &mut Ui, result: &mut Option<Url>) -> &mut Self { pub fn ui(&mut self, ui: &mut Ui, result: &mut Option<Inner::Result>) -> &mut Self {
ui.horizontal(|ui| { ui.horizontal(|ui| {
Checkbox::without_text(&mut self.enabled).ui(ui); Checkbox::without_text(&mut self.enabled).ui(ui);
ui.add_enabled_ui(self.enabled, |ui| { ui.add_enabled_ui(self.enabled, |ui| {
ui.add_sized( let widget = self.inner.widget(ui, &mut self.value, self.error);
ui.available_size(), ui.add_sized(ui.available_size(), widget);
TextEdit::singleline(&mut self.value)
.hint_text(self.hint)
.text_color_opt(if self.error {
Some(ui.style().visuals.error_fg_color)
} else {
None
}),
);
}); });
}); });
if self.enabled { if self.enabled {
match Url::parse(&self.value) { match self.inner.value_to_result(&self.value) {
Ok(url) => { Ok(value) => {
*result = Some(url); *result = Some(value);
self.error = false; self.error = false;
} }
Err(_) => { Err(()) => {
self.error = true; self.error = true;
} }
} }