diff --git a/Cargo.lock b/Cargo.lock index 36b10d2..c4435bc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1022,7 +1022,7 @@ dependencies = [ [[package]] name = "egui_json_tree" version = "0.1.0" -source = "git+https://github.com/dmackdev/egui_json_tree?rev=c9a6909#c9a690945ab45808ae2f2616594a26dbc214e8e8" +source = "git+https://github.com/dmackdev/egui_json_tree?rev=fb20bb3#fb20bb35824123a4a06d34ed8f1f3bf98a569f34" dependencies = [ "egui", "serde_json", diff --git a/pubsubman/Cargo.toml b/pubsubman/Cargo.toml index 4cebba5..38b709d 100644 --- a/pubsubman/Cargo.toml +++ b/pubsubman/Cargo.toml @@ -16,7 +16,7 @@ eframe = { git = "https://github.com/emilk/egui", rev = "481f448", default-featu "glow", # Use the glow rendering backend. Alternative: "wgpu". "persistence", # Enable restoring app state when restarting the app. ] } -egui_json_tree = { git = "https://github.com/dmackdev/egui_json_tree", rev = "c9a6909" } +egui_json_tree = { git = "https://github.com/dmackdev/egui_json_tree", rev = "fb20bb3" } log = "0.4" serde = { workspace = true } diff --git a/pubsubman/src/ui/messages_view.rs b/pubsubman/src/ui/messages_view.rs index 031f804..8d1d882 100644 --- a/pubsubman/src/ui/messages_view.rs +++ b/pubsubman/src/ui/messages_view.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use chrono::{DateTime, Local}; -use egui_json_tree::{DefaultExpand, JsonTree, JsonTreeResponse}; +use egui_json_tree::{DefaultExpand, JsonTreeBuilder, JsonTreeResponse}; use pubsubman_backend::{ message::FrontendMessage, model::{PubsubMessage, SubscriptionName, TopicName}, @@ -20,7 +20,6 @@ pub struct MessagesView { pub stream_messages_enabled: bool, pub stream_messages_cancel_token: Option, pub search_query: String, - copy_popup: Option<(egui::Pos2, String, Value)>, } impl MessagesView { @@ -33,8 +32,6 @@ impl MessagesView { column_settings: &mut ColumnSettings, messages: &[PubsubMessage], ) { - self.show_copy_popup(ui); - let search_query = self.search_query.to_ascii_lowercase(); let filtered_messages = messages .iter() @@ -153,78 +150,16 @@ impl MessagesView { &search_query, ); - for (response, value) in responses { + for response in responses { if search_query_changed { response.reset_expanded(ui); } - - if let Some((response, path)) = response.inner { - if response.secondary_clicked() { - self.copy_popup = Some(( - response - .interact_pointer_pos() - .unwrap_or(response.rect.left_bottom()), - path, - value, - )); - } - } } }); }); } }); } - - fn show_copy_popup(&mut self, ui: &mut egui::Ui) { - let popup_id = ui.make_persistent_id("copy_popup"); - let mut should_close_popup = false; - - if let Some((pos, path, value)) = &self.copy_popup { - let area_response = egui::Area::new(popup_id) - .order(egui::Order::Foreground) - .constrain(true) - .fixed_pos(*pos) - .pivot(egui::Align2::LEFT_TOP) - .show(ui.ctx(), |ui| { - egui::Frame::popup(ui.style()).show(ui, |ui| { - ui.with_layout(egui::Layout::top_down_justified(egui::Align::LEFT), |ui| { - ui.set_width(150.0); - - if !path.is_empty() - && ui - .add(egui::Button::new("Copy property path").frame(false)) - .clicked() - { - ui.output_mut(|o| o.copied_text = path.clone()); - should_close_popup = true; - } - - if ui - .add(egui::Button::new("Copy contents").frame(false)) - .clicked() - { - if let Some(val) = value.pointer(path) { - if let Ok(pretty_str) = serde_json::to_string_pretty(val) { - ui.output_mut(|o| o.copied_text = pretty_str); - } - } - should_close_popup = true; - } - }); - }); - }) - .response; - - if area_response.clicked_elsewhere() { - should_close_popup = true; - } - } - - if should_close_popup { - self.copy_popup = None; - } - } } fn render_messages_table<'a, I>( @@ -233,7 +168,7 @@ fn render_messages_table<'a, I>( column_settings: &ColumnSettings, messages: I, search_term: &str, -) -> Vec<(JsonTreeResponse, Value)> +) -> Vec where I: Iterator, { @@ -301,10 +236,16 @@ where Err(_) => Value::String(message.data.clone()), }; - let response = JsonTree::new(&message.id, &value) - .show(ui, DefaultExpand::SearchResults(search_term)); + let response = JsonTreeBuilder::new(&message.id, &value) + .default_expand(DefaultExpand::SearchResults(search_term)) + .response_callback(|response, pointer| { + response.context_menu(|ui| { + show_context_menu(ui, pointer, &value); + }); + }) + .show(ui); - json_tree_responses.push((response, value)); + json_tree_responses.push(response); ui.end_row(); } @@ -312,6 +253,33 @@ where json_tree_responses } +fn show_context_menu(ui: &mut egui::Ui, pointer: &String, value: &Value) { + ui.with_layout(egui::Layout::top_down_justified(egui::Align::LEFT), |ui| { + ui.set_width(150.0); + + if !pointer.is_empty() + && ui + .add(egui::Button::new("Copy property path").frame(false)) + .clicked() + { + ui.output_mut(|o| o.copied_text = pointer.clone()); + ui.close_menu(); + } + + if ui + .add(egui::Button::new("Copy contents").frame(false)) + .clicked() + { + if let Some(val) = value.pointer(pointer) { + if let Ok(pretty_str) = serde_json::to_string_pretty(val) { + ui.output_mut(|o| o.copied_text = pretty_str); + } + } + ui.close_menu(); + } + }); +} + fn format_attributes(attributes: &HashMap) -> String { attributes .iter()