Markdown renderer for docs
This commit is contained in:
19
Cargo.lock
generated
19
Cargo.lock
generated
@@ -2799,6 +2799,17 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "markdown"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef3aab6a1d529b112695f72beec5ee80e729cb45af58663ec902c8fac764ecdd"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"pipeline",
|
||||
"regex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "matrixmultiply"
|
||||
version = "0.2.4"
|
||||
@@ -2910,6 +2921,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bincode",
|
||||
"bitflags 2.5.0",
|
||||
"bytemuck",
|
||||
"chrono",
|
||||
"clone-macro",
|
||||
@@ -2928,6 +2940,7 @@ dependencies = [
|
||||
"imageproc",
|
||||
"itertools 0.13.0",
|
||||
"libblur",
|
||||
"markdown",
|
||||
"nalgebra 0.32.6",
|
||||
"notify-rust",
|
||||
"open",
|
||||
@@ -3613,6 +3626,12 @@ version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pipeline"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d15b6607fa632996eb8a17c9041cb6071cb75ac057abd45dece578723ea8c7c0"
|
||||
|
||||
[[package]]
|
||||
name = "piper"
|
||||
version = "0.2.3"
|
||||
|
@@ -25,6 +25,7 @@ image = "0.25.1"
|
||||
imageproc = "0.25.0"
|
||||
itertools = "0.13.0"
|
||||
libblur = "0.15.1"
|
||||
markdown = "0.3.0"
|
||||
md5 = "0.7.0"
|
||||
nalgebra = { version = "0.32.6", features = ["serde-serialize"] }
|
||||
notify-rust = "4.11.0"
|
||||
|
11
docs/getting_started.md
Normal file
11
docs/getting_started.md
Normal file
@@ -0,0 +1,11 @@
|
||||
# Getting Started
|
||||
|
||||
Welcome to mslicer!
|
||||
|
||||
Currently, mslicer can only output `.goo` files, which is a format spsific to [ELEGOO](https://www.elegoo.com) resin printers. In the future I plan to add support for other formats, but in the meantime you can use [UVTools](https://github.com/sn4k3/UVtools) to convert between formats.
|
||||
|
||||
If you are using mslicer for the first time, in order for the sliced results to be loadable by your printer, you will first need to configure the platform resolution and build volume in the `Slice Config` panel on the left. The defaults are for the ElEGOO [Saturn 3 Ultra](https://us.elegoo.com/products/elegoo-saturn-3-ultra-resin-3d-printer-12k). If these values are wrong, your printer may fail to load the sliced .goo file without even showing an error message.
|
||||
|
||||
mslicer can load `.stl` and `.obj` models, either by finding the `Import Model` button under the File menu, or by dragging the files onto the window. For now you can load the built in test model (it's the [Utah Teapot](https://en.wikipedia.org/wiki/Utah_teapot)) by pressing `Ctrl+T`.
|
||||
|
||||
To be continued
|
@@ -1,9 +0,0 @@
|
||||
Welcome to mslicer!
|
||||
|
||||
Currently, mslicer can only output .goo files, which is a format spsific to ELEGOO resin printers. In the future I plan to add support for other formats, but in the meantime you can use UVTools to convert between formats.
|
||||
|
||||
If you are using mslicer for the first time, in order for the sliced results to be loadable by your printer, you will first need to configure the platform resolution and build volume in the `Slice Config` panel on the left. The defaults are for the ElEGOO Saturn 3 Ultra. If these values are wrong, your printer may fail to load the sliced .goo file without even showing an error message.
|
||||
|
||||
mslicer can load .stl and .obj models, either by finding the `Import Model` button under the File menu, or by dragging the files onto the window. For now you can load the built in test model (it's the Utah Teapot) by pressing `Ctrl+T`.
|
||||
|
||||
To be continued
|
@@ -6,6 +6,7 @@ edition = "2021"
|
||||
[dependencies]
|
||||
anyhow.workspace = true
|
||||
bincode.workspace = true
|
||||
bitflags.workspace = true
|
||||
bytemuck.workspace = true
|
||||
chrono.workspace = true
|
||||
clone-macro.workspace = true
|
||||
@@ -22,6 +23,7 @@ image.workspace = true
|
||||
imageproc.workspace = true
|
||||
itertools.workspace = true
|
||||
libblur.workspace = true
|
||||
markdown.workspace = true
|
||||
nalgebra.workspace = true
|
||||
notify-rust.workspace = true
|
||||
open.workspace = true
|
||||
|
157
mslicer/src/ui/markdown.rs
Normal file
157
mslicer/src/ui/markdown.rs
Normal file
@@ -0,0 +1,157 @@
|
||||
use bitflags::bitflags;
|
||||
use egui::{Align, Layout, RichText, Sense, TextStyle, Ui, Vec2};
|
||||
use markdown::{Block, Span};
|
||||
|
||||
const BODY_SIZE: f32 = 12.5;
|
||||
const HEADING_SIZES: [f32; 6] = [18.0, 16.0, 14.0, 12.0, 10.0, 8.0];
|
||||
|
||||
pub struct CompiledMarkdown {
|
||||
nodes: Vec<Node>,
|
||||
}
|
||||
|
||||
enum Node {
|
||||
Body(Vec<BodyNode>),
|
||||
Break,
|
||||
}
|
||||
|
||||
enum BodyNode {
|
||||
Text {
|
||||
text: String,
|
||||
size: f32,
|
||||
flags: TextFlags,
|
||||
},
|
||||
Link {
|
||||
text: String,
|
||||
url: String,
|
||||
},
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
#[derive(Clone, Copy)]
|
||||
struct TextFlags: u8 {
|
||||
const HEADER = 1 << 0;
|
||||
const WEAK = 1 << 1;
|
||||
const BOLD = 1 << 2;
|
||||
const ITALIC = 1 << 3;
|
||||
const MONOSPACE = 1 << 4;
|
||||
}
|
||||
}
|
||||
|
||||
impl TextFlags {
|
||||
pub fn apply(&self, mut text: RichText) -> RichText {
|
||||
if self.contains(TextFlags::HEADER) {
|
||||
text = text.heading();
|
||||
}
|
||||
|
||||
if self.contains(TextFlags::WEAK) {
|
||||
text = text.weak();
|
||||
}
|
||||
|
||||
if self.contains(TextFlags::BOLD) {
|
||||
text = text.strong();
|
||||
}
|
||||
|
||||
if self.contains(TextFlags::ITALIC) {
|
||||
text = text.italics();
|
||||
}
|
||||
|
||||
if self.contains(TextFlags::MONOSPACE) {
|
||||
text = text.monospace();
|
||||
}
|
||||
|
||||
text
|
||||
}
|
||||
}
|
||||
|
||||
impl CompiledMarkdown {
|
||||
pub fn compile(source: &str) -> Self {
|
||||
let mut nodes = Vec::new();
|
||||
|
||||
for token in markdown::tokenize(source) {
|
||||
match token {
|
||||
Block::Header(span, level) => {
|
||||
let mut flags = TextFlags::HEADER;
|
||||
|
||||
if level > 1 {
|
||||
flags |= TextFlags::WEAK;
|
||||
}
|
||||
|
||||
nodes.push(Node::Body(span_text(span, HEADING_SIZES[level - 1], flags)));
|
||||
nodes.push(Node::Break);
|
||||
}
|
||||
Block::Paragraph(span) => {
|
||||
nodes.push(Node::Body(span_text(span, BODY_SIZE, TextFlags::empty())));
|
||||
nodes.push(Node::Break);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
Self { nodes }
|
||||
}
|
||||
|
||||
pub fn render(&self, ui: &mut Ui) {
|
||||
ui.allocate_ui_with_layout(
|
||||
Vec2::new(ui.available_width(), ui.spacing().interact_size.y),
|
||||
Layout::left_to_right(Align::Max).with_main_wrap(true),
|
||||
|ui| {
|
||||
let row_height = ui.text_style_height(&TextStyle::Heading);
|
||||
ui.set_row_height(row_height);
|
||||
ui.spacing_mut().item_spacing.x = 0.0;
|
||||
|
||||
for node in self.nodes.iter() {
|
||||
match node {
|
||||
Node::Body(body_nodes) => {
|
||||
for node in body_nodes {
|
||||
match node {
|
||||
BodyNode::Text { text, size, flags } => {
|
||||
ui.label(flags.apply(RichText::new(text).size(*size)));
|
||||
}
|
||||
BodyNode::Link { text, url } => {
|
||||
ui.hyperlink_to(text, url).on_hover_text(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Node::Break => {
|
||||
ui.allocate_exact_size(Vec2::new(0.0, row_height), Sense::hover());
|
||||
ui.end_row();
|
||||
ui.set_row_height(row_height);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn span_text(span: Vec<Span>, size: f32, flags: TextFlags) -> Vec<BodyNode> {
|
||||
fn span_text_inner(out: &mut Vec<BodyNode>, span: &[Span], size: f32, flags: TextFlags) {
|
||||
for node in span {
|
||||
match node {
|
||||
Span::Text(text) => out.push(BodyNode::Text {
|
||||
text: text.to_owned(),
|
||||
flags,
|
||||
size,
|
||||
}),
|
||||
Span::Code(text) => out.push(BodyNode::Text {
|
||||
text: text.to_owned(),
|
||||
flags: flags | TextFlags::MONOSPACE,
|
||||
size,
|
||||
}),
|
||||
Span::Link(text, url, _) => out.push(BodyNode::Link {
|
||||
text: text.to_owned(),
|
||||
url: url.to_owned(),
|
||||
}),
|
||||
Span::Emphasis(vec) => span_text_inner(out, vec, size, flags | TextFlags::ITALIC),
|
||||
Span::Strong(vec) => span_text_inner(out, vec, size, flags | TextFlags::BOLD),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut out = Vec::new();
|
||||
span_text_inner(&mut out, &span, size, flags);
|
||||
|
||||
out
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
pub mod components;
|
||||
pub mod drag_and_drop;
|
||||
pub mod markdown;
|
||||
pub mod popup;
|
||||
pub mod state;
|
||||
|
@@ -1,25 +1,23 @@
|
||||
use egui::{Context, Ui};
|
||||
|
||||
use crate::app::App;
|
||||
use crate::{app::App, ui::markdown::CompiledMarkdown};
|
||||
|
||||
const DESCRIPTION: &str = "A work in progress FOSS slicer for resin printers, created by Connor Slade. Source code is available on Github at ";
|
||||
const GITHUB_LINK: &str = "https://github.com/connorslade/mslicer";
|
||||
|
||||
pub fn ui(app: &mut App, ui: &mut Ui, _ctx: &Context) {
|
||||
ui.monospace(concat!("mslicer v", env!("CARGO_PKG_VERSION")));
|
||||
ui.horizontal_wrapped(|ui| {
|
||||
ui.spacing_mut().item_spacing.x = 0.0;
|
||||
ui.label(DESCRIPTION);
|
||||
ui.hyperlink_to(
|
||||
"@connorslade/mslicer",
|
||||
"https://github.com/connorslade/mslicer",
|
||||
);
|
||||
ui.hyperlink_to("@connorslade/mslicer", GITHUB_LINK)
|
||||
.on_hover_text(GITHUB_LINK);
|
||||
ui.label(".");
|
||||
});
|
||||
|
||||
ui.add_space(16.0);
|
||||
ui.heading("Getting Started");
|
||||
|
||||
ui.label(include_str!("../../../docs/getting_started.txt"));
|
||||
CompiledMarkdown::compile(include_str!("../../../docs/getting_started.md")).render(ui);
|
||||
|
||||
ui.add_space(16.0);
|
||||
ui.heading("Stats");
|
||||
|
Reference in New Issue
Block a user