Skip to content

Commit 18227f2

Browse files
authored
Merge pull request #821 from multiplex55/codex/refactor-notegraphdialog-layout-management
Refactor note graph dialog to use explicit canvas/details layout sizing
2 parents aee41c4 + 06d9a5a commit 18227f2

1 file changed

Lines changed: 123 additions & 15 deletions

File tree

src/gui/note_graph_dialog.rs

Lines changed: 123 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,11 @@ use std::collections::BTreeSet;
1414

1515
const MIN_ZOOM: f32 = 0.2;
1616
const MAX_ZOOM: f32 = 2.5;
17+
const MIN_CANVAS_WIDTH: f32 = 300.0;
18+
const DETAILS_WIDTH_RATIO: f32 = 0.28;
19+
const DETAILS_MIN: f32 = 180.0;
20+
const DETAILS_MAX: f32 = 280.0;
21+
const MIN_CANVAS_HEIGHT: f32 = 300.0;
1722

1823
#[derive(Default, Deserialize)]
1924
struct NoteGraphDialogArgs {
@@ -227,18 +232,37 @@ impl NoteGraphDialog {
227232
persist_requested |= self.filters_top_panel(ui, &notes);
228233
ui.separator();
229234

230-
ui.horizontal(|ui| {
231-
ui.set_min_height(ui.available_height());
232-
let available_width = ui.available_width().max(320.0);
233-
let right_panel_width = (available_width * 0.28).clamp(180.0, 280.0);
234-
ui.vertical(|ui| self.main_canvas(ui, ctx, app));
235-
if self.show_details_panel {
236-
ui.separator();
237-
persist_requested |= ui
238-
.vertical(|ui| self.right_panel(ui, app, &notes, right_panel_width))
239-
.inner;
240-
}
235+
let available_rect = ui.available_rect_before_wrap();
236+
let total_width = available_rect.width();
237+
let total_height = available_rect.height().max(MIN_CANVAS_HEIGHT);
238+
let panel_rect = Rect::from_min_size(
239+
available_rect.min,
240+
egui::vec2(total_width.max(MIN_CANVAS_WIDTH), total_height),
241+
);
242+
ui.allocate_rect(panel_rect, Sense::hover());
243+
244+
let (canvas_width, details_width) =
245+
compute_graph_layout(panel_rect.width(), self.show_details_panel);
246+
let canvas_rect =
247+
Rect::from_min_size(panel_rect.min, egui::vec2(canvas_width, total_height));
248+
let details_rect = details_width.map(|width| {
249+
Rect::from_min_size(
250+
Pos2::new(canvas_rect.right(), panel_rect.top()),
251+
egui::vec2(width, total_height),
252+
)
253+
});
254+
255+
ui.allocate_ui_at_rect(canvas_rect, |ui| {
256+
self.main_canvas(ui, ctx, app, canvas_rect.size())
241257
});
258+
259+
if let Some((details_rect, details_width)) = details_rect.zip(details_width) {
260+
persist_requested |= ui
261+
.allocate_ui_at_rect(details_rect, |ui| {
262+
self.right_panel(ui, app, &notes, details_width)
263+
})
264+
.inner;
265+
}
242266
});
243267
self.open = window_open;
244268
self.was_open_last_frame = self.open;
@@ -525,10 +549,16 @@ impl NoteGraphDialog {
525549
changed
526550
}
527551

528-
fn main_canvas(&mut self, ui: &mut egui::Ui, ctx: &egui::Context, app: &mut LauncherApp) {
552+
fn main_canvas(
553+
&mut self,
554+
ui: &mut egui::Ui,
555+
ctx: &egui::Context,
556+
app: &mut LauncherApp,
557+
canvas_size: Vec2,
558+
) {
529559
let desired = egui::vec2(
530-
ui.available_width().max(300.0),
531-
ui.available_height().max(300.0),
560+
canvas_size.x.max(MIN_CANVAS_WIDTH),
561+
canvas_size.y.max(MIN_CANVAS_HEIGHT),
532562
);
533563
let (rect, response) = ui.allocate_exact_size(desired, Sense::click_and_drag());
534564
let painter = ui.painter_at(rect);
@@ -662,7 +692,7 @@ impl NoteGraphDialog {
662692
width: f32,
663693
) -> bool {
664694
ui.set_min_width(width);
665-
ui.set_max_width(width + 24.0);
695+
ui.set_max_width(width);
666696
ui.label("Details");
667697
let Some(slug) = self.selected_node_id.as_deref() else {
668698
ui.label("Select a node");
@@ -743,6 +773,19 @@ impl NoteGraphDialog {
743773
}
744774
}
745775

776+
fn compute_graph_layout(total_width: f32, details_visible: bool) -> (f32, Option<f32>) {
777+
let total_width = total_width.max(0.0);
778+
if !details_visible {
779+
return (total_width.max(MIN_CANVAS_WIDTH), None);
780+
}
781+
782+
let details_width = (total_width * DETAILS_WIDTH_RATIO)
783+
.clamp(DETAILS_MIN, DETAILS_MAX)
784+
.min((total_width - MIN_CANVAS_WIDTH).max(0.0));
785+
let canvas_width = (total_width - details_width).max(MIN_CANVAS_WIDTH);
786+
(canvas_width, Some(details_width))
787+
}
788+
746789
fn normalize_tag(tag: &str) -> String {
747790
tag.trim()
748791
.trim_start_matches('#')
@@ -866,4 +909,69 @@ mod tests {
866909
assert!(dlg.open);
867910
assert!(dlg.pending_args.is_some());
868911
}
912+
913+
#[test]
914+
fn compute_graph_layout_table_driven_cases() {
915+
struct Case {
916+
total_width: f32,
917+
details_visible: bool,
918+
expected_canvas: f32,
919+
expected_details: Option<f32>,
920+
}
921+
922+
let cases = [
923+
Case {
924+
total_width: 260.0,
925+
details_visible: false,
926+
expected_canvas: MIN_CANVAS_WIDTH,
927+
expected_details: None,
928+
},
929+
Case {
930+
total_width: 420.0,
931+
details_visible: true,
932+
expected_canvas: MIN_CANVAS_WIDTH,
933+
expected_details: Some(120.0),
934+
},
935+
Case {
936+
total_width: 1000.0,
937+
details_visible: true,
938+
expected_canvas: 720.0,
939+
expected_details: Some(280.0),
940+
},
941+
Case {
942+
total_width: 1000.0,
943+
details_visible: false,
944+
expected_canvas: 1000.0,
945+
expected_details: None,
946+
},
947+
];
948+
949+
for case in cases {
950+
let (canvas, details) = compute_graph_layout(case.total_width, case.details_visible);
951+
assert!((canvas - case.expected_canvas).abs() < f32::EPSILON);
952+
match (details, case.expected_details) {
953+
(Some(actual), Some(expected)) => {
954+
assert!((actual - expected).abs() < f32::EPSILON);
955+
}
956+
(None, None) => {}
957+
_ => panic!(
958+
"details width mismatch for total width {}",
959+
case.total_width
960+
),
961+
}
962+
}
963+
}
964+
965+
#[test]
966+
fn details_visible_canvas_only_shrinks_by_computed_details_width() {
967+
let total_width = 900.0;
968+
let (hidden_canvas, hidden_details) = compute_graph_layout(total_width, false);
969+
let (visible_canvas, visible_details) = compute_graph_layout(total_width, true);
970+
971+
assert_eq!(hidden_details, None);
972+
let details_width = visible_details.expect("details panel should have a width");
973+
assert!((hidden_canvas - total_width).abs() < f32::EPSILON);
974+
assert!((visible_canvas - (hidden_canvas - details_width)).abs() < f32::EPSILON);
975+
assert!((visible_canvas + details_width - total_width).abs() < f32::EPSILON);
976+
}
869977
}

0 commit comments

Comments
 (0)