lib.rs (3672B)
1 pub mod anim; 2 pub mod app_images; 3 pub mod colors; 4 pub mod constants; 5 pub mod contacts_list; 6 pub mod context_menu; 7 pub mod debug; 8 pub mod header; 9 pub mod icons; 10 pub mod images; 11 pub mod media; 12 pub mod mention; 13 pub mod nip51_set; 14 pub mod note; 15 pub mod profile; 16 mod username; 17 pub mod widgets; 18 19 pub use anim::{rolling_number, AnimationHelper, PulseAlpha}; 20 pub use contacts_list::{ContactsListAction, ContactsListView}; 21 pub use debug::debug_slider; 22 pub use icons::{expanding_button, ICON_EXPANSION_MULTIPLE, ICON_WIDTH}; 23 pub use mention::Mention; 24 pub use note::{NoteContents, NoteOptions, NoteView}; 25 pub use profile::{ProfilePic, ProfilePreview}; 26 pub use username::Username; 27 28 use egui::{Label, Margin, Pos2, RichText}; 29 30 /// This is kind of like the Widget trait but is meant for larger top-level 31 /// views that are typically stateful. 32 /// 33 /// The Widget trait forces us to add mutable 34 /// implementations at the type level, which screws us when generating Previews 35 /// for a Widget. I would have just Widget instead of making this Trait otherwise. 36 /// 37 /// There is some precendent for this, it looks like there's a similar trait 38 /// in the egui demo library. 39 pub trait View { 40 fn ui(&mut self, ui: &mut egui::Ui); 41 } 42 43 pub fn padding<R>( 44 amount: impl Into<Margin>, 45 ui: &mut egui::Ui, 46 add_contents: impl FnOnce(&mut egui::Ui) -> R, 47 ) -> egui::InnerResponse<R> { 48 egui::Frame::new() 49 .inner_margin(amount) 50 .show(ui, add_contents) 51 } 52 53 pub fn hline(ui: &egui::Ui) { 54 hline_with_width(ui, ui.available_rect_before_wrap().x_range()); 55 } 56 57 pub fn hline_with_width(ui: &egui::Ui, range: egui::Rangef) { 58 // pixel perfect horizontal line 59 let rect = ui.available_rect_before_wrap(); 60 #[allow(deprecated)] 61 let resize_y = ui.painter().round_to_pixel(rect.top()) - 0.5; 62 let stroke = ui.style().visuals.widgets.noninteractive.bg_stroke; 63 ui.painter().hline(range, resize_y, stroke); 64 } 65 66 pub fn secondary_label(ui: &mut egui::Ui, s: impl Into<String>) -> egui::Response { 67 let color = ui.style().visuals.noninteractive().fg_stroke.color; 68 ui.add(Label::new(RichText::new(s).size(10.0).color(color)).selectable(false)) 69 } 70 71 const INPUT_RECT_KEY: &str = "notedeck_input_rect"; 72 73 /// Includes an input rect for keyboard visibility purposes. We use this to move the screen up if 74 /// a soft keyboard intersects with the input box 75 pub fn include_input(ui: &mut egui::Ui, resp: &egui::Response) { 76 // only include input if we have focus 77 if !resp.has_focus() { 78 return; 79 } 80 81 ui.data_mut(|d| { 82 let id = egui::Id::new(INPUT_RECT_KEY); 83 match d.get_temp::<egui::Rect>(id) { 84 Some(r) => d.insert_temp(id, resp.rect.union(r)), 85 None => d.insert_temp(id, resp.rect), 86 } 87 }) 88 } 89 90 /// Set the last input rect for keyboard visibility purposes. We use this to move the screen up if 91 /// a soft keyboard intersects with the input box 92 pub fn input_rect(ui: &mut egui::Ui) -> Option<egui::Rect> { 93 ui.data(|d| d.get_temp(egui::Id::new(INPUT_RECT_KEY))) 94 } 95 96 /// Set the last input rect for keyboard visibility purposes. We use this to move the screen up if 97 /// a soft keyboard intersects with the input box 98 pub fn clear_input_rect(ui: &mut egui::Ui) { 99 ui.data_mut(|d| d.remove::<egui::Rect>(egui::Id::new(INPUT_RECT_KEY))) 100 } 101 102 /// Center the galley on the center pos, returning the position of the top left position of the galley, 103 /// for the `painter.galley(..)` 104 pub fn galley_centered_pos(galley: &std::sync::Arc<egui::Galley>, center: Pos2) -> Pos2 { 105 let mut top_left = center; 106 top_left.x -= galley.rect.width() / 2.0; 107 top_left.y -= galley.rect.height() / 2.0; 108 109 top_left 110 }