114 lines
3.7 KiB
Rust
114 lines
3.7 KiB
Rust
//! block trait and layered view compositor interface.
|
|
|
|
use iced_wgpu::core::{Element, Point, Theme};
|
|
use crate::text_widget;
|
|
|
|
use crate::selection::{BlockId, InnerPath, NodePath, Selection};
|
|
use crate::table_block::TableMessage;
|
|
|
|
/// z-ordering layers for the document compositor.
|
|
#[repr(u8)]
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
|
pub enum Layer {
|
|
/// cursorline highlights, selection background tints.
|
|
Below = 0,
|
|
/// structural body of the block.
|
|
Content = 1,
|
|
/// selection borders, focus rings, eval result tags.
|
|
Above = 2,
|
|
/// drag previews, ghosted reorder anchors.
|
|
Floating = 3,
|
|
}
|
|
|
|
/// layered output from a block's view, merged by the compositor in layer order.
|
|
pub struct LayeredView<'a, Message> {
|
|
/// main structural element, rendered in document order.
|
|
pub base: Element<'a, Message, Theme, iced_wgpu::Renderer>,
|
|
/// overlays tagged with their target layer.
|
|
pub overlays: Vec<(Layer, Element<'a, Message, Theme, iced_wgpu::Renderer>)>,
|
|
}
|
|
|
|
impl<'a, Message> LayeredView<'a, Message> {
|
|
/// constructs a LayeredView with no overlays.
|
|
pub fn just(base: Element<'a, Message, Theme, iced_wgpu::Renderer>) -> Self {
|
|
Self { base, overlays: Vec::new() }
|
|
}
|
|
}
|
|
|
|
/// shared rendering context passed into every Block::view call.
|
|
pub struct ViewCtx<'a, Message: 'a> {
|
|
pub block_index: usize,
|
|
pub selection: &'a Selection,
|
|
pub focus: Option<&'a NodePath>,
|
|
pub editing: Option<&'a NodePath>,
|
|
pub font_size: f32,
|
|
pub is_dark: bool,
|
|
pub on_text_action: fn(usize, text_widget::Action) -> Message,
|
|
pub on_table_msg: fn(usize, TableMessage) -> Message,
|
|
/// evaluated formula results keyed by (block id, col, row).
|
|
pub computed_cells: &'a std::collections::HashMap<
|
|
(BlockId, u32, u32),
|
|
acord_core::interp::Value,
|
|
>,
|
|
}
|
|
|
|
/// structural mutation commands routed to a specific block by the editor.
|
|
#[derive(Debug, Clone)]
|
|
pub enum BlockCommand {
|
|
// Table commands
|
|
InsertRowAbove(usize),
|
|
InsertRowBelow(usize),
|
|
DeleteRow(usize),
|
|
InsertColLeft(usize),
|
|
InsertColRight(usize),
|
|
DeleteCol(usize),
|
|
SetCellValue { row: usize, col: usize, value: String },
|
|
ResizeCol { col: usize, width: f32 },
|
|
ResizeRow { row: usize, height: f32 },
|
|
MoveCol { from: usize, to: usize },
|
|
MoveRow { from: usize, to: usize },
|
|
// Heading commands
|
|
SetHeadingLevel(u8),
|
|
SetHeadingText(String),
|
|
// Generic
|
|
SelectAll,
|
|
Clear,
|
|
}
|
|
|
|
/// protocol every block kind implements, generic over the editor's message type.
|
|
pub trait Block<Message> {
|
|
fn id(&self) -> BlockId;
|
|
fn kind_tag(&self) -> &'static str;
|
|
|
|
/// document-relative line where the block begins.
|
|
fn start_line(&self) -> usize;
|
|
fn set_start_line(&mut self, line: usize);
|
|
|
|
/// number of lines the block contributes to the document.
|
|
fn line_count(&self) -> usize;
|
|
|
|
/// marks blocks produced by eval rather than parsed from markdown.
|
|
fn is_eval_result(&self) -> bool {
|
|
false
|
|
}
|
|
|
|
/// downcast to concrete block types.
|
|
fn as_any(&self) -> &dyn std::any::Any;
|
|
fn as_any_mut(&mut self) -> &mut dyn std::any::Any;
|
|
|
|
/// renders the block into layered output for the compositor.
|
|
fn view<'a>(&'a self, ctx: &ViewCtx<'_, Message>) -> LayeredView<'a, Message>;
|
|
|
|
/// serializes the block as plain markdown.
|
|
fn to_md(&self) -> String;
|
|
|
|
/// resolves a local-space point to the innermost selectable path.
|
|
fn hit_test(&self, point: Point) -> Option<InnerPath>;
|
|
|
|
/// applies a structural mutation, ignoring unsupported commands.
|
|
fn apply(&mut self, cmd: BlockCommand);
|
|
|
|
/// iterates all selectable inner paths in the block (non-recursive).
|
|
fn selectable_paths(&self) -> Box<dyn Iterator<Item = InnerPath> + '_>;
|
|
}
|