desktop: Made OptionalUrlField an OptionalField<UrlField>
This commit is contained in:
parent
9d6d945ca4
commit
34c994a28f
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue