notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

widgets.rs (5056B)


      1 use crate::anim::{AnimationHelper, ICON_EXPANSION_MULTIPLE};
      2 use crate::icons::search_icon;
      3 use egui::{emath::GuiRounding, Align, Color32, CornerRadius, Pos2, RichText, Stroke, TextEdit};
      4 use notedeck::NotedeckTextStyle;
      5 
      6 pub fn x_button(rect: egui::Rect) -> impl egui::Widget {
      7     move |ui: &mut egui::Ui| -> egui::Response {
      8         let max_width = rect.width();
      9         let helper = AnimationHelper::new_from_rect(ui, "user_search_close", rect);
     10 
     11         let fill_color = ui.visuals().text_color();
     12 
     13         let radius = max_width / (2.0 * ICON_EXPANSION_MULTIPLE);
     14 
     15         let painter = ui.painter();
     16         let ppp = ui.ctx().pixels_per_point();
     17         let nw_edge = helper
     18             .scale_pos_from_center(Pos2::new(-radius, radius))
     19             .round_to_pixel_center(ppp);
     20         let se_edge = helper
     21             .scale_pos_from_center(Pos2::new(radius, -radius))
     22             .round_to_pixel_center(ppp);
     23         let sw_edge = helper
     24             .scale_pos_from_center(Pos2::new(-radius, -radius))
     25             .round_to_pixel_center(ppp);
     26         let ne_edge = helper
     27             .scale_pos_from_center(Pos2::new(radius, radius))
     28             .round_to_pixel_center(ppp);
     29 
     30         let line_width = helper.scale_1d_pos(2.0);
     31 
     32         painter.line_segment([nw_edge, se_edge], Stroke::new(line_width, fill_color));
     33         painter.line_segment([ne_edge, sw_edge], Stroke::new(line_width, fill_color));
     34 
     35         helper.take_animation_response()
     36     }
     37 }
     38 
     39 /// Button styled in the Notedeck theme
     40 pub fn styled_button_toggleable(
     41     text: &str,
     42     fill_color: egui::Color32,
     43     enabled: bool,
     44 ) -> impl egui::Widget + '_ {
     45     move |ui: &mut egui::Ui| -> egui::Response {
     46         let painter = ui.painter();
     47         let text_color = if ui.visuals().dark_mode {
     48             egui::Color32::WHITE
     49         } else {
     50             egui::Color32::BLACK
     51         };
     52 
     53         let galley = painter.layout(
     54             text.to_owned(),
     55             NotedeckTextStyle::Button.get_font_id(ui.ctx()),
     56             text_color,
     57             ui.available_width(),
     58         );
     59 
     60         let size = galley.rect.expand2(egui::vec2(16.0, 8.0)).size();
     61         let mut button = egui::Button::new(galley).corner_radius(8.0);
     62 
     63         if !enabled {
     64             button = button
     65                 .sense(egui::Sense::focusable_noninteractive())
     66                 .fill(ui.visuals().noninteractive().bg_fill)
     67                 .stroke(ui.visuals().noninteractive().bg_stroke);
     68         } else {
     69             button = button.fill(fill_color);
     70         }
     71 
     72         let mut resp = ui.add_sized(size, button);
     73 
     74         if !enabled {
     75             resp = resp.on_hover_cursor(egui::CursorIcon::NotAllowed);
     76         }
     77 
     78         resp
     79     }
     80 }
     81 
     82 /// Get appropriate background color for active side panel icon button
     83 pub fn side_panel_active_bg(ui: &egui::Ui) -> egui::Color32 {
     84     if ui.visuals().dark_mode {
     85         egui::Color32::from_rgb(70, 70, 70)
     86     } else {
     87         egui::Color32::from_rgb(220, 220, 220)
     88     }
     89 }
     90 
     91 /// Get appropriate tint color for side panel icons to ensure visibility
     92 pub fn side_panel_icon_tint(ui: &egui::Ui) -> egui::Color32 {
     93     if ui.visuals().dark_mode {
     94         egui::Color32::WHITE
     95     } else {
     96         egui::Color32::BLACK
     97     }
     98 }
     99 
    100 /// Returns a styled Frame for search input boxes with rounded corners.
    101 pub fn search_input_frame(dark_mode: bool) -> egui::Frame {
    102     egui::Frame {
    103         inner_margin: egui::Margin::symmetric(8, 0),
    104         outer_margin: egui::Margin::ZERO,
    105         corner_radius: CornerRadius::same(18),
    106         shadow: Default::default(),
    107         fill: if dark_mode {
    108             Color32::from_rgb(30, 30, 30)
    109         } else {
    110             Color32::from_rgb(240, 240, 240)
    111         },
    112         stroke: if dark_mode {
    113             Stroke::new(1.0, Color32::from_rgb(60, 60, 60))
    114         } else {
    115             Stroke::new(1.0, Color32::from_rgb(200, 200, 200))
    116         },
    117     }
    118 }
    119 
    120 /// The standard height for search input boxes.
    121 pub const SEARCH_INPUT_HEIGHT: f32 = 34.0;
    122 
    123 /// A styled search input box with rounded corners and search icon.
    124 pub fn search_input_box<'a>(query: &'a mut String, hint_text: &'a str) -> impl egui::Widget + 'a {
    125     move |ui: &mut egui::Ui| -> egui::Response {
    126         ui.horizontal(|ui| {
    127             search_input_frame(ui.visuals().dark_mode)
    128                 .show(ui, |ui| {
    129                     ui.with_layout(egui::Layout::left_to_right(Align::Center), |ui| {
    130                         ui.spacing_mut().item_spacing = egui::vec2(8.0, 0.0);
    131 
    132                         ui.add(search_icon(16.0, SEARCH_INPUT_HEIGHT));
    133 
    134                         ui.add_sized(
    135                             [ui.available_width(), SEARCH_INPUT_HEIGHT],
    136                             TextEdit::singleline(query)
    137                                 .hint_text(RichText::new(hint_text).weak())
    138                                 .margin(egui::vec2(0.0, 8.0))
    139                                 .frame(false),
    140                         )
    141                     })
    142                     .inner
    143                 })
    144                 .inner
    145         })
    146         .response
    147     }
    148 }