Compare commits

...

1 commit

Author SHA1 Message Date
Emil Ernerfeldt
dc46f5957e [EasyMark] WIP: small and raised text 2021-03-21 11:00:28 +01:00
5 changed files with 91 additions and 14 deletions

View file

@ -13,6 +13,7 @@
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Item<'a> { pub enum Item<'a> {
/// `\n` /// `\n`
// TODO: add Style here so empty heading still uses up the right amount of space.
Newline, Newline,
/// ///
Text(Style, &'a str), Text(Style, &'a str),
@ -48,6 +49,10 @@ pub struct Style {
pub strikethrough: bool, pub strikethrough: bool,
/// /italics/ /// /italics/
pub italics: bool, pub italics: bool,
/// $small$
pub small: bool,
/// ^raised^
pub raised: bool,
} }
/// Parser for the `EasyMark` markup language. /// Parser for the `EasyMark` markup language.
@ -292,6 +297,18 @@ impl<'a> Iterator for Parser<'a> {
self.style.italics = !self.style.italics; self.style.italics = !self.style.italics;
continue; continue;
} }
if let Some(rest) = self.s.strip_prefix('$') {
self.s = rest;
self.start_of_line = false;
self.style.small = !self.style.small;
continue;
}
if let Some(rest) = self.s.strip_prefix('^') {
self.s = rest;
self.start_of_line = false;
self.style.raised = !self.style.raised;
continue;
}
// `<url>` or `[link](url)` // `<url>` or `[link](url)`
if let Some(item) = self.url() { if let Some(item) = self.url() {
@ -301,7 +318,7 @@ impl<'a> Iterator for Parser<'a> {
// Swallow everything up to the next special character: // Swallow everything up to the next special character:
let end = self let end = self
.s .s
.find(&['*', '`', '~', '_', '/', '\\', '<', '[', '\n'][..]) .find(&['*', '`', '~', '_', '/', '$', '^', '\\', '<', '[', '\n'][..])
.map(|special| special.max(1)) // make sure we swallow at least one character .map(|special| special.max(1)) // make sure we swallow at least one character
.unwrap_or_else(|| self.s.len()); .unwrap_or_else(|| self.s.len());

View file

@ -84,12 +84,19 @@ fn label_from_style(text: &str, style: &easy_mark::Style) -> Label {
underline, underline,
strikethrough, strikethrough,
italics, italics,
small,
raised,
} = *style; } = *style;
let small = small || raised; // Raised text is also smaller
let mut label = Label::new(text); let mut label = Label::new(text);
if heading { if heading && !small {
label = label.heading().strong(); label = label.heading().strong();
} }
if small && !heading {
label = label.small();
}
if code { if code {
label = label.code(); label = label.code();
} }
@ -107,6 +114,9 @@ fn label_from_style(text: &str, style: &easy_mark::Style) -> Label {
if italics { if italics {
label = label.italics(); label = label.italics();
} }
if raised {
label = label.raised();
}
label label
} }

View file

@ -23,6 +23,7 @@ pub struct Label {
strikethrough: bool, strikethrough: bool,
underline: bool, underline: bool,
italics: bool, italics: bool,
raised: bool,
} }
impl Label { impl Label {
@ -39,6 +40,7 @@ impl Label {
strikethrough: false, strikethrough: false,
underline: false, underline: false,
italics: false, italics: false,
raised: false,
} }
} }
@ -112,10 +114,22 @@ impl Label {
self self
} }
/// Smaller text
pub fn small(self) -> Self { pub fn small(self) -> Self {
self.text_style(TextStyle::Small) self.text_style(TextStyle::Small)
} }
/// For e.g. exponents
pub fn small_raised(self) -> Self {
self.text_style(TextStyle::Small).raised()
}
/// Align text to top
pub fn raised(mut self) -> Self {
self.raised = true;
self
}
/// Fill-color behind the text /// Fill-color behind the text
pub fn background_color(mut self, background_color: impl Into<Color32>) -> Self { pub fn background_color(mut self, background_color: impl Into<Color32>) -> Self {
self.background_color = background_color.into(); self.background_color = background_color.into();
@ -171,6 +185,7 @@ impl Label {
strikethrough, strikethrough,
underline, underline,
italics, italics,
raised: _, // TODO
.. ..
} = *self; } = *self;
@ -257,6 +272,7 @@ impl Widget for Label {
let text_style = self.text_style_or_default(ui.style()); let text_style = self.text_style_or_default(ui.style());
let font = &ui.fonts()[text_style]; let font = &ui.fonts()[text_style];
let font_height = font.row_height();
let mut galley = font.layout_multiline_with_indentation_and_max_width( let mut galley = font.layout_multiline_with_indentation_and_max_width(
self.text.clone(), self.text.clone(),
first_row_indentation, first_row_indentation,
@ -270,18 +286,35 @@ impl Widget for Label {
let id = ui.advance_cursor_after_rect(rect); let id = ui.advance_cursor_after_rect(rect);
let mut response = ui.interact(rect, id, sense); let mut response = ui.interact(rect, id, sense);
let mut y_translation = 0.0; // We could be sharing the first row with e.g. a button which is higher than text.
if let Some(row) = galley.rows.get(1) { // So we need to compensate for that:
// We could be sharing the first row with e.g. a button, that is higher than text. if let Some(row) = galley.rows.get_mut(1) {
// So we need to compensate for that: let cursor = ui.cursor();
if pos.y + row.y_min < ui.min_rect().bottom() {
y_translation = ui.min_rect().bottom() - row.y_min - pos.y; if pos.y + row.y_min < cursor.bottom() {
let y_translation = cursor.bottom() - row.y_min - pos.y;
if y_translation != 0.0 {
for row in galley.rows.iter_mut().skip(1) {
row.y_min += y_translation;
row.y_max += y_translation;
}
}
}
}
if text_style == TextStyle::Small && !self.raised {
for row in galley.rows.iter_mut() {
// center:
let normal_text_heigth = ui.fonts()[TextStyle::Body].row_height(); // TODO: get from ui
let dy = (normal_text_heigth - font_height) / 2.0;
row.y_min += dy;
row.y_max += dy;
} }
} }
for row in galley.rows.iter_mut().skip(1) { for row in galley.rows.iter_mut().skip(1) {
row.y_min += y_translation;
row.y_max += y_translation;
let rect = row.rect().translate(vec2(pos.x, pos.y)); let rect = row.rect().translate(vec2(pos.x, pos.y));
response |= ui.allocate_rect(rect, sense); response |= ui.allocate_rect(rect, sense);
} }

View file

@ -13,7 +13,7 @@ pub(crate) struct State {
#[derive(Clone, Copy, Debug, Default)] #[derive(Clone, Copy, Debug, Default)]
#[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))] #[cfg_attr(feature = "persistence", derive(serde::Deserialize, serde::Serialize))]
struct CursorPair { pub struct CursorPair {
/// When selecting with a mouse, this is where the mouse was released. /// When selecting with a mouse, this is where the mouse was released.
/// When moving with e.g. shift+arrows, this is what moves. /// When moving with e.g. shift+arrows, this is what moves.
/// Note that the two ends can come in any order, and also be equal (no selection). /// Note that the two ends can come in any order, and also be equal (no selection).
@ -133,6 +133,14 @@ pub struct TextEdit<'t> {
desired_width: Option<f32>, desired_width: Option<f32>,
desired_height_rows: usize, desired_height_rows: usize,
} }
impl<'t> TextEdit<'t> {
pub fn cursor(ui: &Ui, id: Id) -> Option<CursorPair> {
ui.memory()
.text_edit
.get(&id)
.and_then(|state| state.cursorp)
}
}
impl<'t> TextEdit<'t> { impl<'t> TextEdit<'t> {
#[deprecated = "Use `TextEdit::singleline` or `TextEdit::multiline` (or the helper `ui.text_edit_singleline`, `ui.text_edit_multiline`) instead"] #[deprecated = "Use `TextEdit::singleline` or `TextEdit::multiline` (or the helper `ui.text_edit_singleline`, `ui.text_edit_multiline`) instead"]

View file

@ -37,8 +37,9 @@ impl EasyMarkEditor {
ScrollArea::auto_sized() ScrollArea::auto_sized()
.id_source("source") .id_source("source")
.show(&mut columns[0], |ui| { .show(&mut columns[0], |ui| {
// ui.text_edit_multiline(&mut self.code);
ui.add(TextEdit::multiline(&mut self.code).text_style(TextStyle::Monospace)); ui.add(TextEdit::multiline(&mut self.code).text_style(TextStyle::Monospace));
// let cursor = TextEdit::cursor(response.id);
// TODO: cmd-i, cmd-b, etc for italics, bold, ....
}); });
ScrollArea::auto_sized() ScrollArea::auto_sized()
.id_source("rendered") .id_source("rendered")
@ -62,7 +63,7 @@ and is also missing some features.
# At a glance # At a glance
- inline text: - inline text:
- normal, `code`, *strong*, ~strikethrough~, _underline_, /italics/ - normal, `code`, *strong*, ~strikethrough~, _underline_, /italics/, ^raised^, $small$
- `\` escapes the next character - `\` escapes the next character
- [hyperlink](https://github.com/emilk/egui) - [hyperlink](https://github.com/emilk/egui)
- Embedded URL: <https://github.com/emilk/egui> - Embedded URL: <https://github.com/emilk/egui>
@ -72,6 +73,8 @@ and is also missing some features.
- `- ` bullet list - `- ` bullet list
- `1. ` numbered list - `1. ` numbered list
- \`\`\` code fence - \`\`\` code fence
- You can write exponents like so: x^2^
- Remember to read the small print $(terms and conditions apply)$
# Design # Design
> /"Why do what everyone else is doing, when everyone else is already doing it?" > /"Why do what everyone else is doing, when everyone else is already doing it?"
@ -102,9 +105,11 @@ Escaping the newline effectively ignores it.
The style characters are chosen to be similar to what they are representing: The style characters are chosen to be similar to what they are representing:
`_` = _underline_ `_` = _underline_
`~` = ~strikethrough~ (`-` is too common in normal text) `~` = ~strikethrough~ (`-` is used for bullet points)
`/` = /italics/ `/` = /italics/
`*` = *strong* `*` = *strong*
`$` = $small$
`^` = ^raised^
# TODO # TODO
- Sub-headers (`## h2`, `### h3` etc) - Sub-headers (`## h2`, `### h3` etc)
@ -113,5 +118,9 @@ The style characters are chosen to be similar to what they are representing:
- centering of images is very desirable - centering of images is very desirable
- captioning (image with a text underneath it) - captioning (image with a text underneath it)
- `![caption=My image][width=200][center](url)` ? - `![caption=My image][width=200][center](url)` ?
- Nicer URL:s
- `<url>` and `[url](url)` do the same thing yet look completely different.
- let's keep similarity with images
- Tables - Tables
- <https://mycorrhiza.lesarbr.es/page/mycomarkup>
"#; "#;