use std::hash::{Hash, Hasher};
use egui::{self, Color32, DragValue, Grid, Ui};
#[derive(Clone, Debug, PartialEq)]
pub struct MarkdownStyle {
pub inline_code: InlineCodeStyle,
pub code_block: CodeBlockStyle,
pub heading: HeadingStyle,
pub horizontal_rule: HorizontalRuleStyle,
pub blockquote: BlockquoteStyle,
pub block_spacing: f32,
pub code_font_size: f32,
pub default_code_language: String,
}
impl Default for MarkdownStyle {
fn default() -> Self {
Self {
inline_code: InlineCodeStyle::default(),
code_block: CodeBlockStyle::default(),
heading: HeadingStyle::default(),
horizontal_rule: HorizontalRuleStyle::default(),
blockquote: BlockquoteStyle::default(),
block_spacing: 8.0,
code_font_size: 10.0,
default_code_language: String::new(),
}
}
}
impl Hash for MarkdownStyle {
fn hash<H: Hasher>(&self, state: &mut H) {
self.inline_code.hash(state);
self.code_block.hash(state);
self.heading.hash(state);
self.horizontal_rule.hash(state);
self.blockquote.hash(state);
self.block_spacing.to_bits().hash(state);
self.code_font_size.to_bits().hash(state);
self.default_code_language.hash(state);
}
}
impl MarkdownStyle {
pub fn ui(&mut self, ui: &mut Ui) {
ui.horizontal(|ui| {
let dark_mode = ui.visuals().dark_mode;
if ui.selectable_label(dark_mode, "Dark").clicked() {
ui.ctx().set_visuals(egui::Visuals::dark());
}
if ui.selectable_label(!dark_mode, "Light").clicked() {
ui.ctx().set_visuals(egui::Visuals::light());
}
ui.separator();
if ui.button("Reset").clicked() {
*self = Self::default();
}
});
ui.separator();
ui.label("Block spacing:");
ui.add(DragValue::new(&mut self.block_spacing).range(0.0..=40.0).speed(0.5));
ui.separator();
egui::CollapsingHeader::new("Inline Code").default_open(true).show(ui, |ui| {
self.inline_code.ui(ui);
});
egui::CollapsingHeader::new("Code Blocks").default_open(true).show(ui, |ui| {
self.code_block.ui(ui);
ui.separator();
ui.horizontal(|ui| {
ui.label("Font size:");
ui.add(DragValue::new(&mut self.code_font_size).range(6.0..=30.0).speed(0.5));
});
});
egui::CollapsingHeader::new("Headings").default_open(true).show(ui, |ui| {
self.heading.ui(ui);
});
egui::CollapsingHeader::new("Horizontal Rules").default_open(false).show(ui, |ui| {
self.horizontal_rule.ui(ui);
});
egui::CollapsingHeader::new("Blockquotes").default_open(false).show(ui, |ui| {
self.blockquote.ui(ui);
});
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct InlineCodeStyle {
pub color_dark: Color32,
pub color_light: Color32,
pub background_dark: Color32,
pub background_light: Color32,
pub expand_bg: f32,
}
impl Default for InlineCodeStyle {
fn default() -> Self {
Self {
color_dark: Color32::from_rgb(255, 152, 0),
color_light: Color32::from_rgb(204, 102, 0),
background_dark: Color32::from_gray(50),
background_light: Color32::from_gray(225),
expand_bg: 3.0,
}
}
}
impl Hash for InlineCodeStyle {
fn hash<H: Hasher>(&self, state: &mut H) {
self.color_dark.hash(state);
self.color_light.hash(state);
self.background_dark.hash(state);
self.background_light.hash(state);
self.expand_bg.to_bits().hash(state);
}
}
impl InlineCodeStyle {
pub fn color(&self, dark_mode: bool) -> Color32 {
if dark_mode {
self.color_dark
} else {
self.color_light
}
}
pub fn background(&self, dark_mode: bool) -> Color32 {
if dark_mode {
self.background_dark
} else {
self.background_light
}
}
fn ui(&mut self, ui: &mut Ui) {
Grid::new("inline_code_style").num_columns(2).striped(true).show(ui, |ui| {
ui.label("Color (dark):");
ui.color_edit_button_srgba(&mut self.color_dark);
ui.end_row();
ui.label("Color (light):");
ui.color_edit_button_srgba(&mut self.color_light);
ui.end_row();
ui.label("Background (dark):");
ui.color_edit_button_srgba(&mut self.background_dark);
ui.end_row();
ui.label("Background (light):");
ui.color_edit_button_srgba(&mut self.background_light);
ui.end_row();
ui.label("Expand bg:");
ui.add(DragValue::new(&mut self.expand_bg).range(0.0..=10.0).speed(0.1));
ui.end_row();
});
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct CodeBlockStyle {
pub padding: [f32; 4],
pub corner_radius: f32,
pub stroke_width: f32,
}
impl Default for CodeBlockStyle {
fn default() -> Self {
Self { padding: [4.0, 6.0, 12.0, 6.0], corner_radius: 3.0, stroke_width: 1.0 }
}
}
impl Hash for CodeBlockStyle {
fn hash<H: Hasher>(&self, state: &mut H) {
for v in &self.padding {
v.to_bits().hash(state);
}
self.corner_radius.to_bits().hash(state);
self.stroke_width.to_bits().hash(state);
}
}
impl CodeBlockStyle {
fn ui(&mut self, ui: &mut Ui) {
Grid::new("code_block_style").num_columns(2).striped(true).show(ui, |ui| {
ui.label("Padding left:");
ui.add(DragValue::new(&mut self.padding[0]).range(0.0..=30.0).speed(0.5));
ui.end_row();
ui.label("Padding top:");
ui.add(DragValue::new(&mut self.padding[1]).range(0.0..=30.0).speed(0.5));
ui.end_row();
ui.label("Padding right:");
ui.add(DragValue::new(&mut self.padding[2]).range(0.0..=30.0).speed(0.5));
ui.end_row();
ui.label("Padding bottom:");
ui.add(DragValue::new(&mut self.padding[3]).range(0.0..=30.0).speed(0.5));
ui.end_row();
ui.label("Corner radius:");
ui.add(DragValue::new(&mut self.corner_radius).range(0.0..=20.0).speed(0.5));
ui.end_row();
ui.label("Stroke width:");
ui.add(DragValue::new(&mut self.stroke_width).range(0.0..=5.0).speed(0.1));
ui.end_row();
});
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct HeadingStyle {
pub scales: [f32; 6],
}
impl Default for HeadingStyle {
fn default() -> Self {
Self { scales: [1.6, 1.35, 1.2, 1.1, 1.05, 1.0] }
}
}
impl Hash for HeadingStyle {
fn hash<H: Hasher>(&self, state: &mut H) {
for v in &self.scales {
v.to_bits().hash(state);
}
}
}
impl HeadingStyle {
fn ui(&mut self, ui: &mut Ui) {
Grid::new("heading_style").num_columns(2).striped(true).show(ui, |ui| {
for (i, scale) in self.scales.iter_mut().enumerate() {
ui.label(format!("H{}:", i + 1));
ui.add(DragValue::new(scale).range(0.5..=4.0).speed(0.01));
ui.end_row();
}
});
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct HorizontalRuleStyle {
pub stroke_width: f32,
}
impl Default for HorizontalRuleStyle {
fn default() -> Self {
Self { stroke_width: 1.0 }
}
}
impl Hash for HorizontalRuleStyle {
fn hash<H: Hasher>(&self, state: &mut H) {
self.stroke_width.to_bits().hash(state);
}
}
impl HorizontalRuleStyle {
fn ui(&mut self, ui: &mut Ui) {
Grid::new("hr_style").num_columns(2).striped(true).show(ui, |ui| {
ui.label("Stroke width:");
ui.add(DragValue::new(&mut self.stroke_width).range(0.0..=5.0).speed(0.1));
ui.end_row();
});
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct BlockquoteStyle {
pub indent_per_depth: f32,
pub stroke_width: f32,
}
impl Default for BlockquoteStyle {
fn default() -> Self {
Self { indent_per_depth: 12.0, stroke_width: 1.0 }
}
}
impl Hash for BlockquoteStyle {
fn hash<H: Hasher>(&self, state: &mut H) {
self.indent_per_depth.to_bits().hash(state);
self.stroke_width.to_bits().hash(state);
}
}
impl BlockquoteStyle {
fn ui(&mut self, ui: &mut Ui) {
Grid::new("blockquote_style").num_columns(2).striped(true).show(ui, |ui| {
ui.label("Indent per depth:");
ui.add(DragValue::new(&mut self.indent_per_depth).range(0.0..=40.0).speed(0.5));
ui.end_row();
ui.label("Stroke width:");
ui.add(DragValue::new(&mut self.stroke_width).range(0.0..=5.0).speed(0.1));
ui.end_row();
});
}
}