color mentions in PostView
Signed-off-by: kernelkind <kernelkind@gmail.com>
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
use egui::TextBuffer;
|
use egui::{text::LayoutJob, TextBuffer, TextFormat};
|
||||||
use enostr::{FullKeypair, Pubkey};
|
use enostr::{FullKeypair, Pubkey};
|
||||||
use nostrdb::{Note, NoteBuilder, NoteReply};
|
use nostrdb::{Note, NoteBuilder, NoteReply};
|
||||||
use std::{
|
use std::{
|
||||||
@@ -351,6 +351,70 @@ impl PostBuffer {
|
|||||||
mentions,
|
mentions,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_layout_job(&self, ui: &egui::Ui) -> LayoutJob {
|
||||||
|
let mut job = LayoutJob::default();
|
||||||
|
let colored_fmt = default_text_format_colored(ui, crate::colors::PINK);
|
||||||
|
|
||||||
|
let mut prev_text_char_index = 0;
|
||||||
|
let mut prev_text_byte_index = 0;
|
||||||
|
for (start_char_index, mention_ind) in &self.mention_starts {
|
||||||
|
if let Some(info) = self.mentions.get(mention_ind) {
|
||||||
|
if matches!(info.mention_type, MentionType::Finalized(_)) {
|
||||||
|
let end_char_index = info.end_index;
|
||||||
|
|
||||||
|
let char_indices = prev_text_char_index..*start_char_index;
|
||||||
|
if let Some(byte_indicies) =
|
||||||
|
char_indices_to_byte(&self.text_buffer, char_indices.clone())
|
||||||
|
{
|
||||||
|
if let Some(prev_text) = self.text_buffer.get(byte_indicies.clone()) {
|
||||||
|
job.append(prev_text, 0.0, default_text_format(ui));
|
||||||
|
prev_text_char_index = *start_char_index;
|
||||||
|
prev_text_byte_index = byte_indicies.end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let char_indices = *start_char_index..end_char_index;
|
||||||
|
if let Some(byte_indicies) =
|
||||||
|
char_indices_to_byte(&self.text_buffer, char_indices.clone())
|
||||||
|
{
|
||||||
|
if let Some(cur_text) = self.text_buffer.get(byte_indicies.clone()) {
|
||||||
|
job.append(cur_text, 0.0, colored_fmt.clone());
|
||||||
|
prev_text_char_index = end_char_index;
|
||||||
|
prev_text_byte_index = byte_indicies.end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if prev_text_byte_index < self.text_buffer.len() {
|
||||||
|
if let Some(cur_text) = self.text_buffer.get(prev_text_byte_index..) {
|
||||||
|
job.append(cur_text, 0.0, default_text_format(ui));
|
||||||
|
} else {
|
||||||
|
error!(
|
||||||
|
"could not retrieve substring from [{} to {}) in PostBuffer::text_buffer",
|
||||||
|
prev_text_byte_index,
|
||||||
|
self.text_buffer.len()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
job
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn char_indices_to_byte(text: &str, char_range: Range<usize>) -> Option<Range<usize>> {
|
||||||
|
let mut char_indices = text.char_indices();
|
||||||
|
|
||||||
|
let start = char_indices.nth(char_range.start)?.0;
|
||||||
|
let end = if char_range.end < text.chars().count() {
|
||||||
|
char_indices.nth(char_range.end - char_range.start - 1)?.0
|
||||||
|
} else {
|
||||||
|
text.len()
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(start..end)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn downcast_post_buffer(buffer: &dyn TextBuffer) -> Option<&PostBuffer> {
|
pub fn downcast_post_buffer(buffer: &dyn TextBuffer) -> Option<&PostBuffer> {
|
||||||
@@ -365,6 +429,19 @@ pub fn downcast_post_buffer(buffer: &dyn TextBuffer) -> Option<&PostBuffer> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn default_text_format(ui: &egui::Ui) -> TextFormat {
|
||||||
|
default_text_format_colored(
|
||||||
|
ui,
|
||||||
|
ui.visuals()
|
||||||
|
.override_text_color
|
||||||
|
.unwrap_or_else(|| ui.visuals().widgets.inactive.text_color()),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn default_text_format_colored(ui: &egui::Ui, color: egui::Color32) -> TextFormat {
|
||||||
|
TextFormat::simple(egui::FontSelection::default().resolve(ui.style()), color)
|
||||||
|
}
|
||||||
|
|
||||||
pub struct PostOutput {
|
pub struct PostOutput {
|
||||||
pub text: String,
|
pub text: String,
|
||||||
pub mentions: Vec<Pubkey>,
|
pub mentions: Vec<Pubkey>,
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
use crate::draft::{Draft, Drafts, MentionHint};
|
use crate::draft::{Draft, Drafts, MentionHint};
|
||||||
use crate::images::fetch_img;
|
use crate::images::fetch_img;
|
||||||
use crate::media_upload::{nostrbuild_nip96_upload, MediaPath};
|
use crate::media_upload::{nostrbuild_nip96_upload, MediaPath};
|
||||||
use crate::post::{MentionType, NewPost};
|
use crate::post::{downcast_post_buffer, MentionType, NewPost};
|
||||||
use crate::profile::get_display_name;
|
use crate::profile::get_display_name;
|
||||||
use crate::ui::search_results::SearchResultsView;
|
use crate::ui::search_results::SearchResultsView;
|
||||||
use crate::ui::{self, Preview, PreviewConfig};
|
use crate::ui::{self, Preview, PreviewConfig};
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
use egui::text::CCursorRange;
|
use egui::text::{CCursorRange, LayoutJob};
|
||||||
use egui::text_edit::TextEditOutput;
|
use egui::text_edit::TextEditOutput;
|
||||||
use egui::widgets::text_edit::TextEdit;
|
use egui::widgets::text_edit::TextEdit;
|
||||||
use egui::{vec2, Frame, Layout, Margin, Pos2, ScrollArea, Sense};
|
use egui::{vec2, Frame, Layout, Margin, Pos2, ScrollArea, Sense, TextBuffer};
|
||||||
use enostr::{FilledKeypair, FullKeypair, NoteId, Pubkey, RelayPool};
|
use enostr::{FilledKeypair, FullKeypair, NoteId, Pubkey, RelayPool};
|
||||||
use nostrdb::{Ndb, Transaction};
|
use nostrdb::{Ndb, Transaction};
|
||||||
|
|
||||||
@@ -130,10 +130,22 @@ impl<'a> PostView<'a> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut layouter = |ui: &egui::Ui, buf: &dyn TextBuffer, wrap_width: f32| {
|
||||||
|
let mut layout_job = if let Some(post_buffer) = downcast_post_buffer(buf) {
|
||||||
|
post_buffer.to_layout_job(ui)
|
||||||
|
} else {
|
||||||
|
error!("Failed to get custom mentions layouter");
|
||||||
|
text_edit_default_layout(ui, buf.as_str().to_owned(), wrap_width)
|
||||||
|
};
|
||||||
|
layout_job.wrap.max_width = wrap_width;
|
||||||
|
ui.fonts(|f| f.layout_job(layout_job))
|
||||||
|
};
|
||||||
|
|
||||||
let textedit = TextEdit::multiline(&mut self.draft.buffer)
|
let textedit = TextEdit::multiline(&mut self.draft.buffer)
|
||||||
.hint_text(egui::RichText::new("Write a banger note here...").weak())
|
.hint_text(egui::RichText::new("Write a banger note here...").weak())
|
||||||
.frame(false)
|
.frame(false)
|
||||||
.desired_width(ui.available_width());
|
.desired_width(ui.available_width())
|
||||||
|
.layouter(&mut layouter);
|
||||||
|
|
||||||
let out = textedit.show(ui);
|
let out = textedit.show(ui);
|
||||||
|
|
||||||
@@ -584,6 +596,17 @@ fn calculate_mention_hints_pos(out: &TextEditOutput, char_pos: usize) -> egui::P
|
|||||||
out.text_clip_rect.left_bottom()
|
out.text_clip_rect.left_bottom()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn text_edit_default_layout(ui: &egui::Ui, text: String, wrap_width: f32) -> LayoutJob {
|
||||||
|
LayoutJob::simple(
|
||||||
|
text,
|
||||||
|
egui::FontSelection::default().resolve(ui.style()),
|
||||||
|
ui.visuals()
|
||||||
|
.override_text_color
|
||||||
|
.unwrap_or_else(|| ui.visuals().widgets.inactive.text_color()),
|
||||||
|
wrap_width,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
mod preview {
|
mod preview {
|
||||||
|
|
||||||
use crate::media_upload::Nip94Event;
|
use crate::media_upload::Nip94Event;
|
||||||
|
|||||||
Reference in New Issue
Block a user