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