Skip to content
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
28 changes: 7 additions & 21 deletions crates/app/src/shot.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ use plotx_io::xps::{
use plotx_io::{AxisSource, Dim, Domain, NmrData, NmrData2D, PseudoAxis, PseudoKind, QuadMode};

mod craft_shot;
mod thumbnail_shot;

const FIT_LO: f64 = 1.4;
const FIT_HI: f64 = 3.2;
Expand Down Expand Up @@ -76,6 +77,7 @@ enum Op {
Setup,
/// Fit the FID band and frame the result.
LineFit,
Thumbnails,
/// Load a homonuclear COSY plane and open its symmetry-review workflow.
SymmetrySetup,
/// Pin the ordinary readout cursor on the synthetic COSY.
Expand Down Expand Up @@ -138,6 +140,8 @@ const SCENES: &[Scene] = &[
shot(8, "band"),
act(2, Op::LineFit),
shot(10, "fitted"),
act(2, Op::Thumbnails),
shot(8, "canvas_thumbnails"),
// The three widths bracket the Ribbon's width budget: 720 steps the
// low-priority groups down to their Small and Collapsed scales, 900
// catches the first Medium steps, and 1440 shows every group at Large.
Expand Down Expand Up @@ -368,6 +372,7 @@ fn run_op(op: Op, app: &mut PlotxApp, ctx: &egui::Context) -> Result<(), String>
setup(app);
}
Op::LineFit => line_fit(app, ctx)?,
Op::Thumbnails => thumbnail_shot::setup(app),
Op::SymmetrySetup => symmetry_setup(app)?,
Op::InspectCursor => inspect_cursor(app)?,
Op::DeltaCursor => delta_cursor(app)?,
Expand Down Expand Up @@ -773,24 +778,5 @@ fn save_png(path: &Path, image: &egui::ColorImage) -> Result<(), String> {
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn automated_exit_bypasses_dirty_project_prompt() {
let mut app = PlotxApp::new_with_settings(plotx_core::settings::Settings::default());
app.mark_document_dirty();
let ctx = egui::Context::default();

let output = ctx.run_ui(egui::RawInput::default(), |ui| {
request_exit(&mut app, ui.ctx());
});

assert!(app.session.allow_close);
let root = output
.viewport_output
.get(&egui::ViewportId::ROOT)
.expect("root viewport output");
assert!(root.commands.contains(&egui::ViewportCommand::Close));
}
}
#[path = "shot/tests.rs"]
mod tests;
19 changes: 19 additions & 0 deletions crates/app/src/shot/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use super::*;

#[test]
fn automated_exit_bypasses_dirty_project_prompt() {
let mut app = PlotxApp::new_with_settings(plotx_core::settings::Settings::default());
app.mark_document_dirty();
let ctx = egui::Context::default();

let output = ctx.run_ui(egui::RawInput::default(), |ui| {
request_exit(&mut app, ui.ctx());
});

assert!(app.session.allow_close);
let root = output
.viewport_output
.get(&egui::ViewportId::ROOT)
.expect("root viewport output");
assert!(root.commands.contains(&egui::ViewportCommand::Close));
}
18 changes: 18 additions & 0 deletions crates/app/src/shot/thumbnail_shot.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use plotx_core::actions::Action;
use plotx_core::state::{CanvasId, PlotxApp, PrimaryView};

pub(super) fn setup(app: &mut PlotxApp) {
app.session.view = PrimaryView::Canvas;
app.session.ui.close_task_cards();
let mut portrait = app.doc.canvases[0].clone();
portrait.resource_id = CanvasId::new();
portrait.name = "Portrait comparison with a long canvas name".to_owned();
portrait.size_mm = [110.0, 180.0];
portrait.board_pos[0] += 600.0;
app.execute_action(Action::insert_canvas(
app.doc.canvases.len(),
portrait,
app.session.active_canvas,
));
app.activate_canvas(0);
}
11 changes: 8 additions & 3 deletions crates/app/src/ui/canvas/image_painting.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use super::*;
pub(super) fn paint_document(app: &PlotxApp, ci: usize, rect: egui::Rect, painter: &egui::Painter) {
pub(crate) fn canvas_document(app: &PlotxApp, ci: usize) -> plotx_render::Document<'_> {
let canvas = &app.doc.canvases[ci];
let [width, height] = canvas.size_pt();
let mut items = plotx_core::state::document_items(canvas);
Expand Down Expand Up @@ -61,12 +61,17 @@ pub(super) fn paint_document(app: &PlotxApp, ci: usize, rect: egui::Rect, painte
visible: panel_visible && object.visible,
});
}
let document = plotx_render::Document {
plotx_render::Document {
width,
height,
background: canvas.background,
items,
};
}
}

pub(super) fn paint_document(app: &PlotxApp, ci: usize, rect: egui::Rect, painter: &egui::Painter) {
let canvas = &app.doc.canvases[ci];
let document = canvas_document(app, ci);
let zoom = app.session.board.zoom;
let bp = canvas.board_pos;
let detail = workspace_render_detail(painter.ctx(), painter.ctx().input(|input| input.time));
Expand Down
2 changes: 1 addition & 1 deletion crates/app/src/ui/canvas/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ mod cursors;
mod furniture;
mod geometry;
mod image_drop;
mod image_painting;
pub(crate) mod image_painting;
mod selection_painting;
pub(crate) use image_drop::{ImagePanelDropTarget, image_drop_target};
mod integrals;
Expand Down
10 changes: 7 additions & 3 deletions crates/app/src/ui/primary_sidebar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ mod data_browser;
mod layer_controls;
mod layers_tree;
pub(crate) mod selection;
mod thumbnails;
use board_views::board_views_section;
use data_browser::{AnalysisItem, AnalysisKind, DataTree, DatasetNode};
use layer_controls::truncated_selectable;
use selection::*;

pub fn render(app: &mut PlotxApp, ui: &mut Ui) {
Expand Down Expand Up @@ -101,8 +101,12 @@ fn canvas_list(app: &mut PlotxApp, ui: &mut Ui) {
Some(RenameState { target: RenameTarget::Canvas(i), .. }) if *i == ci
);
if renaming {
let row = thumbnails::canvas_row(app, ci, ui, true, "");
let mut rect = row.rect.shrink2(egui::vec2(6.0, 12.0));
rect.min.x += 80.0;
let mut editor = ui.new_child(egui::UiBuilder::new().max_rect(rect));
let rs = app.session.ui.rename.as_mut().unwrap();
match rename_edit(ui, rs, egui::Id::new(("rename_canvas", ci))) {
match rename_edit(&mut editor, rs, egui::Id::new(("rename_canvas", ci))) {
RenameOutcome::Commit(s) => commit = Some((ci, s)),
RenameOutcome::Cancel => cancel = true,
RenameOutcome::Editing => {}
Expand All @@ -111,7 +115,7 @@ fn canvas_list(app: &mut PlotxApp, ui: &mut Ui) {
}
let name = app.doc.canvases[ci].name.clone();
let selected = crate::ui::canvas::frame_is_selected(app, FrameRef::Page(ci));
let resp = truncated_selectable(ui, selected, name);
let resp = thumbnails::canvas_row(app, ci, ui, selected, &name);
if resp.clicked() {
claim_list_keyboard_focus(ui, &resp);
select = Some((ci, select_modifiers(ui)));
Expand Down
78 changes: 78 additions & 0 deletions crates/app/src/ui/primary_sidebar/thumbnails.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
use egui::{Align2, Color32, Rect, Response, Sense, Stroke, StrokeKind, Ui, vec2};
use plotx_core::state::PlotxApp;

pub(super) fn canvas_row(
app: &PlotxApp,
ci: usize,
ui: &mut Ui,
selected: bool,
name: &str,
) -> Response {
let (rect, _) = ui.allocate_exact_size(vec2(ui.available_width(), 64.0), Sense::hover());
let response = ui.interact(
rect,
ui.id()
.with(("canvas_row", app.doc.canvases[ci].resource_id)),
Sense::click(),
);
response.widget_info(|| {
egui::WidgetInfo::selected(
egui::WidgetType::SelectableLabel,
ui.is_enabled(),
selected,
name,
)
});
if !ui.is_rect_visible(rect) {
return response;
}
let visuals = ui.style().interact_selectable(&response, selected);
let painter = ui.painter_at(rect);
if selected || response.hovered() || response.has_focus() {
painter.rect_filled(rect, 4.0, visuals.weak_bg_fill);
painter.rect_stroke(rect, 4.0, visuals.bg_stroke, StrokeKind::Inside);
}
let preview = Rect::from_min_size(rect.min + vec2(6.0, 6.0), vec2(72.0, 52.0));
painter.rect_filled(preview, 2.0, ui.visuals().faint_bg_color);
let document = crate::ui::canvas::image_painting::canvas_document(app, ci);
if document.width.is_finite()
&& document.height.is_finite()
&& document.width > 0.0
&& document.height > 0.0
{
let available = preview.shrink(3.0);
let zoom = (available.width() / document.width).min(available.height() / document.height);
let size = vec2(document.width, document.height) * zoom;
let page = Rect::from_center_size(available.center(), size);
// A thumbnail has its own viewport, independent of board navigation.
plotx_render::screen::paint_document_for_editor_with_detail(
&painter.with_clip_rect(preview.intersect(ui.clip_rect())),
plotx_render::Rect::new(page.left(), page.top(), page.width(), page.height()),
&document,
plotx_render::DocumentViewport {
zoom,
pan: [0.0, 0.0],
},
plotx_render::screen::ScreenRenderDetail::Interactive,
);
painter.rect_stroke(
page,
0.0,
Stroke::new(0.5_f32, Color32::from_gray(150)),
StrokeKind::Inside,
);
}
let text_rect = Rect::from_min_max(
egui::pos2(preview.right() + 8.0, rect.top()),
rect.max - vec2(6.0, 0.0),
);
let galley = egui::WidgetText::from(name).into_galley(
ui,
Some(egui::TextWrapMode::Truncate),
text_rect.width().max(0.0),
egui::TextStyle::Button,
);
let label = Align2::LEFT_CENTER.align_size_within_rect(galley.size(), text_rect);
painter.galley(label.min, galley, visuals.text_color());
response.on_hover_text(name)
}
3 changes: 2 additions & 1 deletion docs/src/content/docs/reference/ui-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ introduces the same regions in walkthrough form.

- **Primary Side Bar** — the left panel. Its **Canvas** mode lists plots,
pages, and saved board views; its **Data** mode shows every dataset and the
results derived from it.
results derived from it. Each canvas row includes a live page thumbnail;
click to select it, double-click its name to rename it, or use its context menu.
- **Canvas** / **the board** — the central area: an infinite board holding
your plots and ordinary data sheets. "Page" is one framed area of the board
that exports as one figure. Drag a page or table-sheet header to place it;
Expand Down
1 change: 1 addition & 0 deletions docs/src/content/docs/zh-cn/reference/ui-overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ PlotX 的界面为英文;手册中加粗的英文词即界面上的原文标

- **主侧栏(Primary Side Bar)**——左侧面板。**Canvas** 模式列出图形、
页面和已保存的画板视野;**Data** 模式显示每个数据集及其派生结果。
每个画布条目都带有实时页面缩略图;单击选择,双击名称重命名,右键打开上下文菜单。
- **画布(Canvas)/ 画板(board)**——中央区域:承载图形与普通数据表的
无限画板。"页面"是画板上的一块带框区域,导出时对应一张图。拖动页面或
数据表标题可调整位置;靠近其他框架时,会吸附到其边缘和框架间的标准间距。
Expand Down
Loading