Skip to content

Refactor JsonTreeStyle #34

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@ JsonTree::new("simple-tree", &value).show(ui);

// Customised:
let response = JsonTree::new("customised-tree", &value)
.style(JsonTreeStyle {
visuals: Some(JsonTreeVisuals {
bool_color: Color32::YELLOW,
..Default::default()
}),
..Default::default()
})
.style(
JsonTreeStyle::new()
.abbreviate_root(true) // Show {...} when the root object is collapsed.
.toggle_buttons_state(ToggleButtonsState::VisibleDisabled)
.visuals(JsonTreeVisuals {
bool_color: Color32::YELLOW,
..Default::default()
}),
)
.default_expand(DefaultExpand::All)
.abbreviate_root(true) // Show {...} when the root object is collapsed.
.toggle_buttons_state(ToggleButtonsState::VisibleDisabled)
.on_render(|ui, ctx| {
// Customise rendering of the JsonTree, and/or handle interactions.
match ctx {
Expand Down
4 changes: 2 additions & 2 deletions examples/demo/src/apps/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ use egui_json_tree::{
DefaultRender, RenderBaseValueContext, RenderContext, RenderExpandableDelimiterContext,
RenderPropertyContext,
},
DefaultExpand, JsonTree,
DefaultExpand, JsonTree, JsonTreeStyle,
};
use serde_json::Value;

Expand Down Expand Up @@ -437,8 +437,8 @@ impl Show for JsonEditorExample {
ui.add_space(10.0);

JsonTree::new(self.title(), &self.value)
.abbreviate_root(true)
.default_expand(DefaultExpand::All)
.style(JsonTreeStyle::new().abbreviate_root(true))
.on_render(|ui, context| self.editor.show(ui, &self.value, context))
.show(ui);

Expand Down
4 changes: 2 additions & 2 deletions examples/demo/src/apps/toggle_buttons.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use egui::Ui;
use egui_json_tree::{DefaultExpand, JsonTree, ToggleButtonsState};
use egui_json_tree::{DefaultExpand, JsonTree, JsonTreeStyle, ToggleButtonsState};
use serde_json::Value;

use super::Show;
Expand Down Expand Up @@ -49,7 +49,7 @@ impl Show for ToggleButtonsCustomisationDemo {

JsonTree::new(self.title(), &self.value)
.default_expand(DefaultExpand::All)
.toggle_buttons_state(self.toggle_buttons_state)
.style(JsonTreeStyle::new().toggle_buttons_state(self.toggle_buttons_state))
.show(ui);
});
}
Expand Down
18 changes: 9 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@
//!
//! // Customised:
//! let response = JsonTree::new("customised-tree", &value)
//! .style(JsonTreeStyle {
//! visuals: Some(JsonTreeVisuals {
//! bool_color: Color32::YELLOW,
//! ..Default::default()
//! }),
//! ..Default::default()
//! })
//! .style(
//! JsonTreeStyle::new()
//! .abbreviate_root(true) // Show {...} when the root object is collapsed.
//! .toggle_buttons_state(ToggleButtonsState::VisibleDisabled)
//! .visuals(JsonTreeVisuals {
//! bool_color: Color32::YELLOW,
//! ..Default::default()
//! }),
//! )
//! .default_expand(DefaultExpand::All)
//! .abbreviate_root(true) // Show {...} when the root object is collapsed.
//! .toggle_buttons_state(ToggleButtonsState::VisibleDisabled)
//! .on_render(|ui, ctx| {
//! // Customise rendering of the JsonTree, and/or handle interactions.
//! match ctx {
Expand Down
23 changes: 10 additions & 13 deletions src/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,12 @@ impl<'a, T: ToJsonTreeValue> JsonTreeNode<'a, T> {
persistent_id.with(tree_id.with(path_segments))
};

let style = config.style.unwrap_or_default();
let default_expand = config.default_expand.unwrap_or_default();

let mut path_id_map = HashMap::new();

let (default_expand, search_term) = match config.default_expand {
let (default_expand, search_term) = match default_expand {
DefaultExpand::All => (InnerExpand::All, None),
DefaultExpand::None => (InnerExpand::None, None),
DefaultExpand::ToLevel(l) => (InnerExpand::ToLevel(l), None),
Expand All @@ -58,7 +61,7 @@ impl<'a, T: ToJsonTreeValue> JsonTreeNode<'a, T> {
let paths = search_term
.as_ref()
.map(|search_term| {
search_term.find_matching_paths_in(self.value, config.abbreviate_root)
search_term.find_matching_paths_in(self.value, style.abbreviate_root)
})
.unwrap_or_default();
(InnerExpand::Paths(paths), search_term)
Expand All @@ -69,17 +72,15 @@ impl<'a, T: ToJsonTreeValue> JsonTreeNode<'a, T> {

let node_config = JsonTreeNodeConfig {
default_expand,
abbreviate_root: config.abbreviate_root,
style: config.style,
style,
search_term,
toggle_buttons_state: config.toggle_buttons_state,
};

// Wrap in a vertical layout in case this tree is placed directly in a horizontal layout,
// which does not allow indent layouts as direct children.
ui.vertical(|ui| {
// Centres the collapsing header icon.
ui.spacing_mut().interact_size.y = node_config.style.font_id(ui).size;
ui.spacing_mut().interact_size.y = node_config.style.resolve_font_id(ui).size;

self.show_impl(
ui,
Expand Down Expand Up @@ -176,10 +177,8 @@ fn show_expandable<'a, 'b, T: ToJsonTreeValue>(
) {
let JsonTreeNodeConfig {
default_expand,
abbreviate_root,
style,
search_term,
toggle_buttons_state,
} = config;

let delimiters = match expandable.expandable_type {
Expand All @@ -204,14 +203,14 @@ fn show_expandable<'a, 'b, T: ToJsonTreeValue>(
let header_res = ui.horizontal_wrapped(|ui| {
ui.spacing_mut().item_spacing.x = 0.0;

if let Some(enabled) = toggle_buttons_state.enabled() {
if let Some(enabled) = style.toggle_buttons_state.enabled() {
ui.add_enabled_ui(enabled, |ui| {
state.show_toggle_button(ui, paint_default_icon)
});
}

if path_segments.is_empty() && !is_expanded {
if *abbreviate_root {
if style.abbreviate_root {
renderer.render_expandable_delimiter(
ui,
RenderExpandableDelimiterContext {
Expand Down Expand Up @@ -381,7 +380,7 @@ fn show_expandable<'a, 'b, T: ToJsonTreeValue>(
}
});

let toggle_buttons_hidden = *toggle_buttons_state == ToggleButtonsState::Hidden;
let toggle_buttons_hidden = style.toggle_buttons_state == ToggleButtonsState::Hidden;
if toggle_buttons_hidden {
ui.visuals_mut().indent_has_left_vline = true;
ui.spacing_mut().indent = (ui.spacing().icon_width + ui.spacing().icon_spacing) / 2.0;
Expand Down Expand Up @@ -450,10 +449,8 @@ fn show_expandable<'a, 'b, T: ToJsonTreeValue>(

struct JsonTreeNodeConfig<'a> {
default_expand: InnerExpand<'a>,
abbreviate_root: bool,
style: JsonTreeStyle,
search_term: Option<SearchTerm>,
toggle_buttons_state: ToggleButtonsState,
}

#[derive(Debug, Clone)]
Expand Down
12 changes: 6 additions & 6 deletions src/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,11 +279,11 @@ fn render_value(
) -> Response {
let job = ui.ctx().memory_mut(|mem| {
mem.caches.cache::<ValueLayoutJobCreatorCache>().get((
style.visuals(ui),
style.resolve_visuals(ui),
value_str,
value_type,
search_term,
&style.font_id(ui),
&style.resolve_font_id(ui),
))
});

Expand Down Expand Up @@ -356,10 +356,10 @@ fn render_property(
) -> Response {
let job = ui.ctx().memory_mut(|mem| {
mem.caches.cache::<PropertyLayoutJobCreatorCache>().get((
style.visuals(ui),
style.resolve_visuals(ui),
property,
search_term,
&style.font_id(ui),
&style.resolve_font_id(ui),
))
});

Expand Down Expand Up @@ -442,9 +442,9 @@ fn render_delimiter(ui: &mut Ui, style: &JsonTreeStyle, delimiter_str: &str) ->
append(
&mut job,
delimiter_str,
style.visuals(ui).punctuation_color,
style.resolve_visuals(ui).punctuation_color,
None,
&style.font_id(ui),
&style.resolve_font_id(ui),
);
render_job(ui, job)
}
Expand Down
46 changes: 41 additions & 5 deletions src/style.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,54 @@
use egui::{Color32, FontId, TextStyle, Ui};

use crate::value::BaseValueType;
use crate::{value::BaseValueType, ToggleButtonsState};

/// Styling configuration to control the appearance of the [`JsonTree`](crate::JsonTree).
#[derive(Debug, Clone, Hash, Default)]
pub struct JsonTreeStyle {
/// The colors to use. If not set, defaults to either a dark or light color scheme, depending on [`egui::Visuals::dark_mode`].
pub visuals: Option<JsonTreeVisuals>,
/// The font to use. If not set, defaults to `TextStyle::Monospace.resolve(ui.style())`.
pub font_id: Option<FontId>,
pub abbreviate_root: bool,
pub toggle_buttons_state: ToggleButtonsState,
}

impl JsonTreeStyle {
pub fn new() -> Self {
Self::default()
}

/// The colors to use. Defaults to either a dark or light color scheme, depending on [`egui::Visuals::dark_mode`].
pub fn visuals(mut self, visuals: JsonTreeVisuals) -> Self {
self.visuals = Some(visuals);
self
}

/// The font to use. Defaults to `TextStyle::Monospace.resolve(ui.style())`.
pub fn font_id(mut self, font_id: FontId) -> Self {
self.font_id = Some(font_id);
self
}

/// Override whether a root array/object should show direct child elements when collapsed.
///
/// If `true`, a collapsed root object would render as: `{...}`.
///
/// If `false`, a collapsed root object would render as: `{ "foo": "bar", "baz": {...} }`.
///
/// Defaults to `false`.
pub fn abbreviate_root(mut self, abbreviate_root: bool) -> Self {
self.abbreviate_root = abbreviate_root;
self
}

/// Override the visibility and interactivity of the toggle buttons for expanding/collapsing objects and arrays.
/// Defaults to [`ToggleButtonsState::VisibleEnabled`].
pub fn toggle_buttons_state(mut self, toggle_buttons_state: ToggleButtonsState) -> Self {
self.toggle_buttons_state = toggle_buttons_state;
self
}

/// Resolves the [`JsonTreeVisuals`] color scheme to use.
pub fn visuals(&self, ui: &Ui) -> &JsonTreeVisuals {
pub(crate) fn resolve_visuals(&self, ui: &Ui) -> &JsonTreeVisuals {
if let Some(visuals) = &self.visuals {
visuals
} else if ui.visuals().dark_mode {
Expand All @@ -23,7 +58,8 @@ impl JsonTreeStyle {
}
}

pub(crate) fn font_id(&self, ui: &Ui) -> FontId {
/// Resolves the [`FontId`] to use.
pub(crate) fn resolve_font_id(&self, ui: &Ui) -> FontId {
if let Some(font_id) = &self.font_id {
font_id.clone()
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/toggle_buttons_state.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/// Setting for the visibility and interactivity of the toggle buttons for expanding/collapsing objects and arrays.
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)]
pub enum ToggleButtonsState {
#[default]
VisibleEnabled,
Expand Down
30 changes: 5 additions & 25 deletions src/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,23 @@ use crate::{
node::JsonTreeNode,
render::{JsonTreeRenderer, RenderContext},
value::ToJsonTreeValue,
DefaultExpand, JsonTreeResponse, JsonTreeStyle, ToggleButtonsState,
DefaultExpand, JsonTreeResponse, JsonTreeStyle,
};
use egui::{Id, Ui};
use std::hash::Hash;

pub(crate) struct JsonTreeConfig<'a, T: ToJsonTreeValue> {
pub(crate) style: JsonTreeStyle,
pub(crate) default_expand: DefaultExpand<'a>,
pub(crate) abbreviate_root: bool,
pub(crate) style: Option<JsonTreeStyle>,
pub(crate) default_expand: Option<DefaultExpand<'a>>,
pub(crate) renderer: JsonTreeRenderer<'a, T>,
pub(crate) toggle_buttons_state: ToggleButtonsState,
}

impl<'a, T: ToJsonTreeValue> Default for JsonTreeConfig<'a, T> {
fn default() -> Self {
Self {
style: Default::default(),
default_expand: Default::default(),
abbreviate_root: Default::default(),
renderer: Default::default(),
toggle_buttons_state: Default::default(),
}
}
}
Expand All @@ -48,13 +44,13 @@ impl<'a, T: ToJsonTreeValue> JsonTree<'a, T> {

/// Override colors for JSON syntax highlighting, and search match highlighting.
pub fn style(mut self, style: JsonTreeStyle) -> Self {
self.config.style = style;
self.config.style = Some(style);
self
}

/// Override how the [`JsonTree`] expands arrays/objects by default.
pub fn default_expand(mut self, default_expand: DefaultExpand<'a>) -> Self {
self.config.default_expand = default_expand;
self.config.default_expand = Some(default_expand);
self
}

Expand Down Expand Up @@ -97,22 +93,6 @@ impl<'a, T: ToJsonTreeValue> JsonTree<'a, T> {
self
}

/// Override whether a root array/object should show direct child elements when collapsed.
///
/// If called with `true`, a collapsed root object would render as: `{...}`.
///
/// Otherwise, a collapsed root object would render as: `{ "foo": "bar", "baz": {...} }`.
pub fn abbreviate_root(mut self, abbreviate_root: bool) -> Self {
self.config.abbreviate_root = abbreviate_root;
self
}

/// Override the visibility and interactivity of the toggle buttons for expanding/collapsing objects and arrays.
pub fn toggle_buttons_state(mut self, toggle_buttons_state: ToggleButtonsState) -> Self {
self.config.toggle_buttons_state = toggle_buttons_state;
self
}

/// Show the JSON tree visualisation within the `Ui`.
pub fn show(self, ui: &mut Ui) -> JsonTreeResponse {
JsonTreeNode::new(self.id, self.value).show_with_config(ui, self.config)
Expand Down
8 changes: 4 additions & 4 deletions tests/json_tree_test.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::sync::Arc;

use egui::{mutex::Mutex, CentralPanel, Context, FontDefinitions, Style};
use egui_json_tree::{render::RenderContext, DefaultExpand, JsonTree};
use egui_json_tree::{render::RenderContext, DefaultExpand, JsonTree, JsonTreeStyle};
#[cfg(feature = "serde_json")]
use serde_json::{json, Value};

Expand Down Expand Up @@ -541,7 +541,7 @@ fn json_tree_reset_expanded() {
CentralPanel::default().show(ctx, |ui| {
JsonTree::new(id, &value)
.default_expand(DefaultExpand::All)
.abbreviate_root(true)
.style(JsonTreeStyle::new().abbreviate_root(true))
.on_render(|_, render_ctx| {
actual.push(render_ctx.into());
})
Expand All @@ -561,7 +561,7 @@ fn json_tree_reset_expanded() {
CentralPanel::default().show(ctx, |ui| {
JsonTree::new(id, &value)
.default_expand(DefaultExpand::None)
.abbreviate_root(true)
.style(JsonTreeStyle::new().abbreviate_root(true))
.on_render(|_, render_ctx| {
actual.push(render_ctx.into());
})
Expand All @@ -581,7 +581,7 @@ fn json_tree_reset_expanded() {
CentralPanel::default().show(ctx, |ui| {
JsonTree::new(id, &value)
.default_expand(DefaultExpand::None)
.abbreviate_root(true)
.style(JsonTreeStyle::new().abbreviate_root(true))
.on_render(|_, render_ctx| {
actual.push(render_ctx.into());
})
Expand Down