Allow changing doc pages

This commit is contained in:
Connor Slade
2025-02-16 15:19:39 -05:00
parent ce2c5f66b1
commit 3b123d4db1
6 changed files with 168 additions and 47 deletions

74
docs/miscellaneous.md Normal file
View File

@@ -0,0 +1,74 @@
# Miscellaneous
This document covers a variety of topics that don't fit into any other category.
## Remote Print HTTP Status Proxy
Part of the process to upload a model to a printer with remote print is to serve the .goo file on a http server, then send the download link to the printer over MQTT. Because remote print already has to run a HTTP server, this option exposes an api at `0.0.0.0:<http_port>/status`. Each time remote print starts all server port are randomized and printed to the log (check the console or the Log panel).
The status route returns an array of printers, each with the following format.
```
struct Printer {
machineId: String,
attributes: Attributes,
status: Status,
lastUpdate: i64,
}
```
The `Attributes` structure is passed directly from the printer's innitial handshake message. I'm honestly not sure what all the fields are for.
```
struct Attributes {
Name: String,
MachineName: String,
ProtocolVersion: String,
FirmwareVersion: String,
Resolution: Resolution,
MainboardIP: String,
MainboardID: String,
SDCPStatus: u8,
LocalSDCPAddress: String,
SDCPAddress: String,
Capabilities: Capability[],
}
enum Capability {
FILE_TRANSFER,
PRINT_CONTROL
}
```
Finally, this data is sent from the printer over MQTT every few seconds.
```
struct Status {
CurrentStatus: CurrentStatus,
PreviousStatus: u8,
PrintInfo: PrintInfo,
FileTransferInfo: FileTransferInfo,
}
enum CurrentStatus {
Ready,
Busy,
TransferringFile
}
enum PrintInfoStatus {
None,
InitialLower,
Lowering,
Exposure,
Retracting,
FinalRetract,
Complete
}
enum FileTransferStatus {
None,
Done,
Error
}
```

View File

@@ -3,3 +3,4 @@
This pages can also be viewed directly in mslcier on the `About` panel.
- [Getting Started](getting_started.md)
- [Miscellaneous](miscellaneous.md)

View File

@@ -1,16 +1,18 @@
use bitflags::bitflags;
use egui::{Align, Layout, RichText, Sense, TextStyle, Ui, Vec2};
use egui::{Align, Layout, RichText, Sense, Shape, TextStyle, Ui, Vec2, Visuals};
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];
#[derive(Default)]
pub struct CompiledMarkdown {
nodes: Vec<Node>,
}
enum Node {
Body(Vec<BodyNode>),
Code(String),
Break,
}
@@ -37,33 +39,11 @@ bitflags! {
}
}
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 is_empty(&self) -> bool {
self.nodes.is_empty()
}
pub fn compile(source: &str) -> Self {
let mut nodes = Vec::new();
@@ -77,14 +57,18 @@ impl CompiledMarkdown {
}
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);
nodes.push(Node::Body(span_text(span, BODY_SIZE, TextFlags::empty())))
}
Block::CodeBlock(_lang, code) => nodes.push(Node::Code(code)),
_ => {}
}
nodes.push(Node::Break);
}
if let Some(Node::Break) = nodes.last() {
nodes.pop();
}
Self { nodes }
@@ -105,7 +89,12 @@ impl CompiledMarkdown {
for node in body_nodes {
match node {
BodyNode::Text { text, size, flags } => {
ui.label(flags.apply(RichText::new(text).size(*size)));
ui.label(
flags.apply(
ui.visuals(),
RichText::new(text).size(*size),
),
);
}
BodyNode::Link { text, url } => {
ui.hyperlink_to(text, url).on_hover_text(url);
@@ -113,6 +102,13 @@ impl CompiledMarkdown {
}
}
}
Node::Code(code) => {
let placeholder = ui.painter().add(Shape::Noop);
let mut rect = ui.monospace(code).rect.expand(1.0);
rect.max.x = ui.max_rect().max.x;
let shape = Shape::rect_filled(rect, 2.0, ui.visuals().code_bg_color);
ui.painter().set(placeholder, shape);
}
Node::Break => {
ui.allocate_exact_size(Vec2::new(0.0, row_height), Sense::hover());
ui.end_row();
@@ -125,6 +121,32 @@ impl CompiledMarkdown {
}
}
impl TextFlags {
pub fn apply(&self, visuals: &Visuals, 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().background_color(visuals.code_bg_color);
}
text
}
}
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 {

View File

@@ -2,6 +2,8 @@ use egui_tracing::EventCollector;
use nalgebra::Vector3;
use slicer::supports::line::LineSupportConfig;
use super::markdown::CompiledMarkdown;
#[derive(Default)]
pub struct UiState {
pub event_collector: EventCollector,
@@ -16,6 +18,7 @@ pub struct UiState {
// documentation
pub docs_page: DocsPage,
pub compiled_markdown: CompiledMarkdown,
}
#[derive(Default, PartialEq, Eq)]
@@ -26,9 +29,27 @@ pub enum RemotePrintConnectStatus {
Scanning,
}
#[derive(Default, PartialEq)]
#[derive(Default, Clone, Copy, PartialEq)]
pub enum DocsPage {
#[default]
GettingStarted,
AnotherPage,
Miscellaneous,
}
impl DocsPage {
pub const ALL: [DocsPage; 2] = [DocsPage::GettingStarted, DocsPage::Miscellaneous];
pub fn name(&self) -> &'static str {
match self {
DocsPage::GettingStarted => "Getting Started",
DocsPage::Miscellaneous => "Miscellaneous",
}
}
pub fn source(&self) -> &'static str {
match self {
DocsPage::GettingStarted => include_str!("../../../docs/getting_started.md"),
DocsPage::Miscellaneous => include_str!("../../../docs/miscellaneous.md"),
}
}
}

View File

@@ -30,20 +30,19 @@ pub fn ui(app: &mut App, ui: &mut Ui, _ctx: &Context) {
});
ui.add_space(8.0);
let last_page = app.state.docs_page;
ui.horizontal(|ui| {
ui.selectable_value(
&mut app.state.docs_page,
DocsPage::GettingStarted,
"Getting Started",
);
ui.selectable_value(
&mut app.state.docs_page,
DocsPage::AnotherPage,
"Another Page",
);
for page in DocsPage::ALL {
ui.selectable_value(&mut app.state.docs_page, page, page.name());
}
});
if last_page != app.state.docs_page || app.state.compiled_markdown.is_empty() {
app.state.compiled_markdown = CompiledMarkdown::compile(app.state.docs_page.source());
}
ui.separator();
CompiledMarkdown::compile(include_str!("../../../docs/getting_started.md")).render(ui);
app.state.compiled_markdown.render(ui);
}

View File

@@ -1,8 +1,8 @@
use const_format::concatcp;
use egui::{Context, Grid, Id, Ui};
use egui_phosphor::regular::{
ARROWS_CLOCKWISE, ARROW_LINE_DOWN, COPY, DICE_THREE, EYE, EYE_SLASH, FLIP_HORIZONTAL, TRASH,
VECTOR_THREE,
ARROWS_CLOCKWISE, ARROW_LINE_DOWN, COPY, DICE_THREE, EYE, EYE_SLASH, FLIP_HORIZONTAL,
LINK_BREAK, LINK_SIMPLE, TRASH, VECTOR_THREE,
};
use slicer::Pos;
@@ -119,7 +119,11 @@ pub fn ui(app: &mut App, ui: &mut Ui, _ctx: &Context) {
(mesh.mesh.scale() != scale).then(|| mesh.mesh.set_scale(scale));
mesh.locked_scale ^= ui
.button(if mesh.locked_scale { "🔒" } else { "🔓" })
.button(if mesh.locked_scale {
LINK_SIMPLE
} else {
LINK_BREAK
})
.clicked();
});
ui.end_row();