Simplify and improve http demo app
Move demo of POST to the ehttp crate instead
This commit is contained in:
parent
1ab61ce9bb
commit
85941033e8
|
|
@ -242,6 +242,14 @@ impl Layout {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn with_main_justify(self, main_justify: bool) -> Self {
|
||||||
|
Self {
|
||||||
|
main_justify,
|
||||||
|
..self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn with_cross_justify(self, cross_justify: bool) -> Self {
|
pub fn with_cross_justify(self, cross_justify: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
|
||||||
|
|
@ -48,10 +48,6 @@ enum Method {
|
||||||
pub struct HttpApp {
|
pub struct HttpApp {
|
||||||
url: String,
|
url: String,
|
||||||
|
|
||||||
method: Method,
|
|
||||||
|
|
||||||
request_body: String,
|
|
||||||
|
|
||||||
#[cfg_attr(feature = "serde", serde(skip))]
|
#[cfg_attr(feature = "serde", serde(skip))]
|
||||||
in_progress: Option<Receiver<Result<ehttp::Response, String>>>,
|
in_progress: Option<Receiver<Result<ehttp::Response, String>>>,
|
||||||
|
|
||||||
|
|
@ -66,8 +62,6 @@ impl Default for HttpApp {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
url: "https://raw.githubusercontent.com/emilk/egui/master/README.md".to_owned(),
|
url: "https://raw.githubusercontent.com/emilk/egui/master/README.md".to_owned(),
|
||||||
method: Method::Get,
|
|
||||||
request_body: r#"["posting some json", { "more_json" : true }]"#.to_owned(),
|
|
||||||
in_progress: Default::default(),
|
in_progress: Default::default(),
|
||||||
result: Default::default(),
|
result: Default::default(),
|
||||||
tex_mngr: Default::default(),
|
tex_mngr: Default::default(),
|
||||||
|
|
@ -80,8 +74,6 @@ impl epi::App for HttpApp {
|
||||||
"⬇ HTTP"
|
"⬇ HTTP"
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called each time the UI needs repainting, which may be many times per second.
|
|
||||||
/// Put your widgets into a `SidePanel`, `TopBottomPanel`, `CentralPanel`, `Window` or `Area`.
|
|
||||||
fn update(&mut self, ctx: &egui::CtxRef, frame: &mut epi::Frame<'_>) {
|
fn update(&mut self, ctx: &egui::CtxRef, frame: &mut epi::Frame<'_>) {
|
||||||
if let Some(receiver) = &mut self.in_progress {
|
if let Some(receiver) = &mut self.in_progress {
|
||||||
// Are we there yet?
|
// Are we there yet?
|
||||||
|
|
@ -91,26 +83,25 @@ impl epi::App for HttpApp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
egui::TopBottomPanel::bottom("http_bottom").show(ctx, |ui| {
|
||||||
|
let layout = egui::Layout::top_down(egui::Align::Center).with_main_justify(true);
|
||||||
|
ui.allocate_ui_with_layout(ui.available_size(), layout, |ui| {
|
||||||
|
ui.add(crate::__egui_github_link_file!())
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
ui.heading("HTTP Fetch Example");
|
let trigger_fetch = ui_url(ui, frame, &mut self.url);
|
||||||
ui.horizontal(|ui| {
|
|
||||||
|
ui.horizontal_wrapped(|ui| {
|
||||||
ui.spacing_mut().item_spacing.x = 0.0;
|
ui.spacing_mut().item_spacing.x = 0.0;
|
||||||
ui.label("HTTP requests made using ");
|
ui.label("HTTP requests made using ");
|
||||||
ui.hyperlink_to("ehttp", "https://www.github.com/emilk/ehttp");
|
ui.hyperlink_to("ehttp", "https://www.github.com/emilk/ehttp");
|
||||||
ui.label(".");
|
ui.label(".");
|
||||||
});
|
});
|
||||||
ui.add(egui::github_link_file!(
|
|
||||||
"https://github.com/emilk/egui/blob/master/",
|
|
||||||
"(demo source code)"
|
|
||||||
));
|
|
||||||
|
|
||||||
if let Some(request) = ui_url(
|
if trigger_fetch {
|
||||||
ui,
|
let request = ehttp::Request::get(&self.url);
|
||||||
frame,
|
|
||||||
&mut self.url,
|
|
||||||
&mut self.method,
|
|
||||||
&mut self.request_body,
|
|
||||||
) {
|
|
||||||
let repaint_signal = frame.repaint_signal();
|
let repaint_signal = frame.repaint_signal();
|
||||||
let (sender, receiver) = std::sync::mpsc::channel();
|
let (sender, receiver) = std::sync::mpsc::channel();
|
||||||
self.in_progress = Some(receiver);
|
self.in_progress = Some(receiver);
|
||||||
|
|
@ -124,7 +115,7 @@ impl epi::App for HttpApp {
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
||||||
if self.in_progress.is_some() {
|
if self.in_progress.is_some() {
|
||||||
ui.label("Please wait...");
|
ui.label("Please wait…");
|
||||||
} else if let Some(result) = &self.result {
|
} else if let Some(result) = &self.result {
|
||||||
match result {
|
match result {
|
||||||
Ok(resource) => {
|
Ok(resource) => {
|
||||||
|
|
@ -143,38 +134,14 @@ impl epi::App for HttpApp {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ui_url(
|
fn ui_url(ui: &mut egui::Ui, frame: &mut epi::Frame<'_>, url: &mut String) -> bool {
|
||||||
ui: &mut egui::Ui,
|
|
||||||
frame: &mut epi::Frame<'_>,
|
|
||||||
url: &mut String,
|
|
||||||
method: &mut Method,
|
|
||||||
request_body: &mut String,
|
|
||||||
) -> Option<ehttp::Request> {
|
|
||||||
let mut trigger_fetch = false;
|
let mut trigger_fetch = false;
|
||||||
|
|
||||||
egui::Grid::new("request_params").show(ui, |ui| {
|
ui.horizontal(|ui| {
|
||||||
ui.label("URL:");
|
ui.label("URL:");
|
||||||
ui.horizontal(|ui| {
|
trigger_fetch |= ui
|
||||||
trigger_fetch |= ui.text_edit_singleline(url).lost_focus();
|
.add(egui::TextEdit::singleline(url).desired_width(f32::INFINITY))
|
||||||
egui::ComboBox::from_id_source("method")
|
.lost_focus();
|
||||||
.selected_text(format!("{:?}", method))
|
|
||||||
.width(60.0)
|
|
||||||
.show_ui(ui, |ui| {
|
|
||||||
ui.selectable_value(method, Method::Get, "GET");
|
|
||||||
ui.selectable_value(method, Method::Post, "POST");
|
|
||||||
});
|
|
||||||
trigger_fetch |= ui.button("▶").clicked();
|
|
||||||
});
|
|
||||||
ui.end_row();
|
|
||||||
if *method == Method::Post {
|
|
||||||
ui.label("Body:");
|
|
||||||
ui.add(
|
|
||||||
egui::TextEdit::multiline(request_body)
|
|
||||||
.code_editor()
|
|
||||||
.desired_rows(1),
|
|
||||||
);
|
|
||||||
ui.end_row();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
if frame.is_web() {
|
if frame.is_web() {
|
||||||
|
|
@ -187,32 +154,17 @@ fn ui_url(
|
||||||
"https://raw.githubusercontent.com/emilk/egui/master/{}",
|
"https://raw.githubusercontent.com/emilk/egui/master/{}",
|
||||||
file!()
|
file!()
|
||||||
);
|
);
|
||||||
*method = Method::Get;
|
|
||||||
trigger_fetch = true;
|
trigger_fetch = true;
|
||||||
}
|
}
|
||||||
if ui.button("Random image").clicked() {
|
if ui.button("Random image").clicked() {
|
||||||
let seed = ui.input().time;
|
let seed = ui.input().time;
|
||||||
let width = 640;
|
let side = 640;
|
||||||
let height = 480;
|
*url = format!("https://picsum.photos/seed/{}/{}", seed, side);
|
||||||
*url = format!("https://picsum.photos/seed/{}/{}/{}", seed, width, height);
|
|
||||||
*method = Method::Get;
|
|
||||||
trigger_fetch = true;
|
|
||||||
}
|
|
||||||
if ui.button("Post to httpbin.org").clicked() {
|
|
||||||
*url = "https://httpbin.org/post".to_owned();
|
|
||||||
*method = Method::Post;
|
|
||||||
trigger_fetch = true;
|
trigger_fetch = true;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if trigger_fetch {
|
trigger_fetch
|
||||||
Some(match *method {
|
|
||||||
Method::Get => ehttp::Request::get(url),
|
|
||||||
Method::Post => ehttp::Request::post(url, request_body),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ui_resource(
|
fn ui_resource(
|
||||||
|
|
@ -244,49 +196,57 @@ fn ui_resource(
|
||||||
|
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
||||||
egui::CollapsingHeader::new("Response headers")
|
|
||||||
.default_open(false)
|
|
||||||
.show(ui, |ui| {
|
|
||||||
egui::Grid::new("response_headers")
|
|
||||||
.spacing(egui::vec2(ui.spacing().item_spacing.x * 2.0, 0.0))
|
|
||||||
.show(ui, |ui| {
|
|
||||||
for header in &response.headers {
|
|
||||||
ui.label(header.0);
|
|
||||||
ui.label(header.1);
|
|
||||||
ui.end_row();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
});
|
|
||||||
|
|
||||||
ui.separator();
|
|
||||||
|
|
||||||
if let Some(text) = &text {
|
|
||||||
let tooltip = "Click to copy the response body";
|
|
||||||
if ui.button("📋").on_hover_text(tooltip).clicked() {
|
|
||||||
ui.output().copied_text = text.clone();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ui.separator();
|
|
||||||
|
|
||||||
egui::ScrollArea::vertical()
|
egui::ScrollArea::vertical()
|
||||||
.auto_shrink([false; 2])
|
.auto_shrink([false; 2])
|
||||||
.show(ui, |ui| {
|
.show(ui, |ui| {
|
||||||
|
egui::CollapsingHeader::new("Response headers")
|
||||||
|
.default_open(false)
|
||||||
|
.show(ui, |ui| {
|
||||||
|
egui::Grid::new("response_headers")
|
||||||
|
.spacing(egui::vec2(ui.spacing().item_spacing.x * 2.0, 0.0))
|
||||||
|
.show(ui, |ui| {
|
||||||
|
for header in &response.headers {
|
||||||
|
ui.label(header.0);
|
||||||
|
ui.label(header.1);
|
||||||
|
ui.end_row();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
ui.separator();
|
||||||
|
|
||||||
|
if let Some(text) = &text {
|
||||||
|
let tooltip = "Click to copy the response body";
|
||||||
|
if ui.button("📋").on_hover_text(tooltip).clicked() {
|
||||||
|
ui.output().copied_text = text.clone();
|
||||||
|
}
|
||||||
|
ui.separator();
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(image) = image {
|
if let Some(image) = image {
|
||||||
if let Some(texture_id) = tex_mngr.texture(frame, &response.url, image) {
|
if let Some(texture_id) = tex_mngr.texture(frame, &response.url, image) {
|
||||||
let size = egui::Vec2::new(image.size.0 as f32, image.size.1 as f32);
|
let mut size = egui::Vec2::new(image.size.0 as f32, image.size.1 as f32);
|
||||||
|
size *= (ui.available_width() / size.x).min(1.0);
|
||||||
ui.image(texture_id, size);
|
ui.image(texture_id, size);
|
||||||
}
|
}
|
||||||
} else if let Some(colored_text) = colored_text {
|
} else if let Some(colored_text) = colored_text {
|
||||||
colored_text.ui(ui);
|
colored_text.ui(ui);
|
||||||
} else if let Some(text) = &text {
|
} else if let Some(text) = &text {
|
||||||
ui.monospace(text);
|
selectable_text(ui, text);
|
||||||
} else {
|
} else {
|
||||||
ui.monospace("[binary]");
|
ui.monospace("[binary]");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn selectable_text(ui: &mut egui::Ui, mut text: &str) {
|
||||||
|
ui.add(
|
||||||
|
egui::TextEdit::multiline(&mut text)
|
||||||
|
.desired_width(f32::INFINITY)
|
||||||
|
.text_style(egui::TextStyle::Monospace),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Syntax highlighting:
|
// Syntax highlighting:
|
||||||
|
|
||||||
|
|
@ -304,28 +264,40 @@ fn syntax_highlighting(
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lines of text fragments
|
|
||||||
struct ColoredText(egui::text::LayoutJob);
|
|
||||||
|
|
||||||
impl ColoredText {
|
|
||||||
#[cfg(feature = "syntect")]
|
|
||||||
pub fn ui(&self, ui: &mut egui::Ui) {
|
|
||||||
let mut job = self.0.clone();
|
|
||||||
job.wrap_width = ui.available_width();
|
|
||||||
let galley = ui.fonts().layout_job(job);
|
|
||||||
let (response, painter) = ui.allocate_painter(galley.size(), egui::Sense::hover());
|
|
||||||
painter.add(egui::Shape::galley(response.rect.min, galley));
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "syntect"))]
|
|
||||||
pub fn ui(&self, _ui: &mut egui::Ui) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "syntect"))]
|
#[cfg(not(feature = "syntect"))]
|
||||||
fn syntax_highlighting(_ctx: &egui::Context, _: &ehttp::Response, _: &str) -> Option<ColoredText> {
|
fn syntax_highlighting(_ctx: &egui::Context, _: &ehttp::Response, _: &str) -> Option<ColoredText> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct ColoredText(egui::text::LayoutJob);
|
||||||
|
|
||||||
|
impl ColoredText {
|
||||||
|
pub fn ui(&self, ui: &mut egui::Ui) {
|
||||||
|
if true {
|
||||||
|
// Selectable text:
|
||||||
|
let mut layouter = |ui: &egui::Ui, _string: &str, wrap_width: f32| {
|
||||||
|
let mut layout_job = self.0.clone();
|
||||||
|
layout_job.wrap_width = wrap_width;
|
||||||
|
ui.fonts().layout_job(layout_job)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut text = self.0.text.as_str();
|
||||||
|
ui.add(
|
||||||
|
egui::TextEdit::multiline(&mut text)
|
||||||
|
.text_style(egui::TextStyle::Monospace)
|
||||||
|
.desired_width(f32::INFINITY)
|
||||||
|
.layouter(&mut layouter),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let mut job = self.0.clone();
|
||||||
|
job.wrap_width = ui.available_width();
|
||||||
|
let galley = ui.fonts().layout_job(job);
|
||||||
|
let (response, painter) = ui.allocate_painter(galley.size(), egui::Sense::hover());
|
||||||
|
painter.add(egui::Shape::galley(response.rect.min, galley));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
// Texture/image handling is very manual at the moment.
|
// Texture/image handling is very manual at the moment.
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue