From ebe4bf30467d364e08b7bca6d5e3f3f26cc32de6 Mon Sep 17 00:00:00 2001 From: kernelkind Date: Fri, 27 Sep 2024 18:53:55 -0400 Subject: [PATCH] animate add column options Signed-off-by: kernelkind --- src/app_style.rs | 13 +++- src/ui/add_column.rs | 168 +++++++++++++++++++++++++++---------------- 2 files changed, 117 insertions(+), 64 deletions(-) diff --git a/src/app_style.rs b/src/app_style.rs index 71a0b7d6..6e9faf60 100644 --- a/src/app_style.rs +++ b/src/app_style.rs @@ -1,5 +1,6 @@ -use crate::colors::{ - desktop_dark_color_theme, light_color_theme, mobile_dark_color_theme, ColorTheme, +use crate::{ + colors::{desktop_dark_color_theme, light_color_theme, mobile_dark_color_theme, ColorTheme}, + ui::is_narrow, }; use egui::{ epaint::Shadow, @@ -96,6 +97,14 @@ pub fn mobile_font_size(text_style: &NotedeckTextStyle) -> f32 { } } +pub fn get_font_size(ctx: &egui::Context, text_style: &NotedeckTextStyle) -> f32 { + if is_narrow(ctx) { + mobile_font_size(text_style) + } else { + desktop_font_size(text_style) + } +} + #[derive(Copy, Clone, Eq, PartialEq, Debug, EnumIter)] pub enum NotedeckTextStyle { Heading, diff --git a/src/ui/add_column.rs b/src/ui/add_column.rs index 3dde0ea3..c75e3c41 100644 --- a/src/ui/add_column.rs +++ b/src/ui/add_column.rs @@ -1,18 +1,20 @@ -use egui::{vec2, ImageSource, Label, Layout, Margin, RichText, Sense, Ui}; +use egui::{pos2, vec2, Color32, FontId, ImageSource, Pos2, Rect, Separator, Ui}; use nostrdb::Ndb; use crate::{ - app_style::NotedeckTextStyle, + app_style::{get_font_size, NotedeckTextStyle}, timeline::{PubkeySource, Timeline, TimelineKind}, + ui::anim::ICON_EXPANSION_MULTIPLE, user_account::UserAccount, }; -use super::padding; +use super::anim::AnimationHelper; pub enum AddColumnResponse { Timeline(Timeline), } +#[derive(Clone)] enum AddColumnOption { Universe, Notification(PubkeySource), @@ -46,76 +48,118 @@ impl<'a> AddColumnView<'a> { } pub fn ui(&mut self, ui: &mut Ui) -> Option { - egui::Frame::none() - .outer_margin(Margin::symmetric(16.0, 20.0)) - .show(ui, |ui| { - ui.label( - RichText::new("Add column").text_style(NotedeckTextStyle::Body.text_style()), - ); - }); - ui.separator(); - - let width_padding = 8.0; - let button_height = 69.0; - let icon_width = 32.0; let mut selected_option: Option = None; for column_option_data in self.get_column_options() { - let width = ui.available_width() - 2.0 * width_padding; - let (rect, resp) = ui.allocate_exact_size(vec2(width, button_height), Sense::click()); - ui.allocate_ui_at_rect(rect, |ui| { - padding(Margin::symmetric(width_padding, 0.0), ui, |ui| { - ui.allocate_ui_with_layout( - vec2(width, button_height), - Layout::left_to_right(egui::Align::Center), - |ui| { - self.column_option_ui( - ui, - icon_width, - column_option_data.icon, - column_option_data.title, - column_option_data.description, - ); - }, - ) - .response - }) - }); - ui.separator(); - - if resp.clicked() { - if let Some(resp) = column_option_data.option.take_as_response(self.ndb) { - selected_option = Some(resp); - } + let option = column_option_data.option.clone(); + if self.column_option_ui(ui, column_option_data).clicked() { + selected_option = option.take_as_response(self.ndb); } + + ui.add(Separator::default().spacing(0.0)); } selected_option } - fn column_option_ui( - &mut self, - ui: &mut Ui, - icon_width: f32, - icon: ImageSource<'_>, - title: &str, - description: &str, - ) { - ui.add(egui::Image::new(icon).fit_to_exact_size(vec2(icon_width, icon_width))); + fn column_option_ui(&mut self, ui: &mut Ui, data: ColumnOptionData) -> egui::Response { + let icon_padding = 8.0; + let min_icon_width = 32.0; + let height_padding = 12.0; + let max_width = ui.available_width(); + let title_style = NotedeckTextStyle::Body; + let desc_style = NotedeckTextStyle::Button; + let title_min_font_size = get_font_size(ui.ctx(), &title_style); + let desc_min_font_size = get_font_size(ui.ctx(), &desc_style); - ui.vertical(|ui| { - ui.add_space(16.0); - ui.add( - Label::new(RichText::new(title).text_style(NotedeckTextStyle::Body.text_style())) - .selectable(false), + let max_height = { + let max_wrap_width = + max_width - ((icon_padding * 2.0) + (min_icon_width * ICON_EXPANSION_MULTIPLE)); + let title_max_font = FontId::new( + title_min_font_size * ICON_EXPANSION_MULTIPLE, + title_style.font_family(), ); - - ui.add( - Label::new( - RichText::new(description).text_style(NotedeckTextStyle::Button.text_style()), + let desc_max_font = FontId::new( + desc_min_font_size * ICON_EXPANSION_MULTIPLE, + desc_style.font_family(), + ); + let max_desc_galley = ui.fonts(|f| { + f.layout( + data.description.to_string(), + desc_max_font, + Color32::WHITE, + max_wrap_width, ) - .selectable(false), - ); - }); + }); + + let max_title_galley = ui.fonts(|f| { + f.layout( + data.title.to_string(), + title_max_font, + Color32::WHITE, + max_wrap_width, + ) + }); + + let desc_font_max_size = max_desc_galley.rect.height(); + let title_font_max_size = max_title_galley.rect.height(); + title_font_max_size + desc_font_max_size + (2.0 * height_padding) + }; + + let helper = AnimationHelper::new(ui, data.title, vec2(max_width, max_height)); + let animation_rect = helper.get_animation_rect(); + + let cur_icon_width = helper.scale_1d_pos(min_icon_width); + let painter = ui.painter_at(animation_rect); + + let cur_icon_size = vec2(cur_icon_width, cur_icon_width); + let cur_icon_x_pos = animation_rect.left() + (icon_padding) + (cur_icon_width / 2.0); + + let title_cur_font = FontId::new( + helper.scale_1d_pos(title_min_font_size), + title_style.font_family(), + ); + + let desc_cur_font = FontId::new( + helper.scale_1d_pos(desc_min_font_size), + desc_style.font_family(), + ); + + let wrap_width = max_width - (cur_icon_width + (icon_padding * 2.0)); + let text_color = ui.ctx().style().visuals.text_color(); + let fallback_color = ui.ctx().style().visuals.weak_text_color(); + + let title_galley = painter.layout( + data.title.to_string(), + title_cur_font, + text_color, + wrap_width, + ); + let desc_galley = painter.layout( + data.description.to_string(), + desc_cur_font, + text_color, + wrap_width, + ); + + let galley_heights = title_galley.rect.height() + desc_galley.rect.height(); + + let cur_height_padding = (animation_rect.height() - galley_heights) / 2.0; + let corner_x_pos = cur_icon_x_pos + (cur_icon_width / 2.0) + icon_padding; + let title_corner_pos = Pos2::new(corner_x_pos, animation_rect.top() + cur_height_padding); + let desc_corner_pos = Pos2::new( + corner_x_pos, + title_corner_pos.y + title_galley.rect.height(), + ); + + let icon_cur_y = animation_rect.top() + cur_height_padding + (galley_heights / 2.0); + let icon_img = egui::Image::new(data.icon).fit_to_exact_size(cur_icon_size); + let icon_rect = Rect::from_center_size(pos2(cur_icon_x_pos, icon_cur_y), cur_icon_size); + + icon_img.paint_at(ui, icon_rect); + painter.galley(title_corner_pos, title_galley, fallback_color); + painter.galley(desc_corner_pos, desc_galley, fallback_color); + + helper.take_animation_response() } fn get_column_options(&self) -> Vec {