Adapt to new iced version, show events in month view

Signed-off-by: Fabrizio Iannetti <fabrizio.iannetti@gmail.com>
This commit is contained in:
Fabrizio Iannetti 2023-05-21 13:41:16 +02:00
parent c805cc94d3
commit ae13e98388
6 changed files with 1491 additions and 640 deletions

1865
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -9,8 +9,7 @@ tracing = ["dep:lttng-ust"]
[dependencies] [dependencies]
#iced = "0.4.2" #iced = "0.4.2"
#iced_native = "0.5.1" #iced_native = "0.5.1"
iced = { path = "../iced" } iced = { path = "../iced", features = ["advanced"] }
iced_native = { path = "../iced/native" }
chrono = "0.4" chrono = "0.4"
lttng-ust = { version = "0.1.0", optional = true } lttng-ust = { version = "0.1.0", optional = true }

View File

@ -9,6 +9,7 @@ use chrono::{Datelike, NaiveDate, Months, Utc};
use calendar::{CalendarMonthView, CalendarYearView, CalendarParams }; use calendar::{CalendarMonthView, CalendarYearView, CalendarParams };
use iced::{ use iced::{
alignment,
executor, executor,
Alignment, Application, Command, Alignment, Application, Command,
Element, Length, Settings, Element, Length, Settings,
@ -100,13 +101,13 @@ impl Controls {
.push( .push(
Text::new(month_name) Text::new(month_name)
.width(Length::Fill) .width(Length::Fill)
.horizontal_alignment(iced_native::alignment::Horizontal::Left) .horizontal_alignment(alignment::Horizontal::Left)
.size(40), .size(40),
) )
.push( .push(
Text::new(year.to_string()) Text::new(year.to_string())
.width(Length::Fill) .width(Length::Fill)
.horizontal_alignment(iced_native::alignment::Horizontal::Right) .horizontal_alignment(alignment::Horizontal::Right)
.size(40), .size(40),
) )
.into() .into()
@ -169,7 +170,7 @@ impl Application for CalendarApp {
match self.controls.mode { match self.controls.mode {
Some(ViewMode::Year) => content = content.push(CalendarYearView::new(&CalendarParams::new(), self.month, &self.events)), Some(ViewMode::Year) => content = content.push(CalendarYearView::new(&CalendarParams::new(), self.month, &self.events)),
Some(ViewMode::Month) | None => content = content.push(CalendarMonthView::new(&CalendarParams::new(), self.month)), Some(ViewMode::Month) | None => content = content.push(CalendarMonthView::new(&CalendarParams::new(), self.month, &self.events)),
}; };
Container::new(content) Container::new(content)

View File

@ -36,14 +36,14 @@ impl EventsCollection {
// TODO: hard-coded events // TODO: hard-coded events
events: vec![ events: vec![
Event { Event {
text: String::from("ev_1"), text: String::from("pentecoste"),
begin: NaiveDate::from_ymd_opt(2023, 01, 15).unwrap(), begin: NaiveDate::from_ymd_opt(2023, 05, 30).unwrap(),
end: NaiveDate::from_ymd_opt(2023, 01, 16).unwrap(), end: NaiveDate::from_ymd_opt(2023, 06, 09).unwrap(),
}, },
Event { Event {
text: String::from("ev_2"), text: String::from("estate"),
begin: NaiveDate::from_ymd_opt(2023, 01, 16).unwrap(), begin: NaiveDate::from_ymd_opt(2023, 07, 31).unwrap(),
end: NaiveDate::from_ymd_opt(2023, 01, 17).unwrap(), end: NaiveDate::from_ymd_opt(2023, 09, 11).unwrap(),
}, },
], ],
} }
@ -57,6 +57,16 @@ impl EventsCollection {
} }
None None
} }
pub fn for_day(&self, day: NaiveDate) -> Vec<Event> {
let mut events_in_day = Vec::new();
for ev_day in &self.events {
if ev_day.is_in_day(day) {
events_in_day.push(ev_day.clone());
}
}
events_in_day
}
} }
impl Default for EventsCollection { impl Default for EventsCollection {

View File

@ -19,7 +19,7 @@ pub struct CellGrid {
width: f32, width: f32,
height: f32, height: f32,
// size fo the grid, in number of cells // size of the grid, in number of cells
num_x: u32, num_x: u32,
num_y: u32, num_y: u32,
@ -46,6 +46,10 @@ impl CellGrid {
} }
} }
pub fn rows(&self) -> Self {
CellGrid::new(self.x, self.y, self.width, self.height, 1, self.num_y)
}
fn compute_cell(&mut self) -> () { fn compute_cell(&mut self) -> () {
self.curr.pos_x = self.pos_x; self.curr.pos_x = self.pos_x;
self.curr.pos_y = self.pos_y; self.curr.pos_y = self.pos_y;

View File

@ -8,12 +8,10 @@
// if you wish to, by creating your own `Renderer` trait, which could be // if you wish to, by creating your own `Renderer` trait, which could be
// implemented by `iced_wgpu` and other renderers. // implemented by `iced_wgpu` and other renderers.
use iced_native::layout::{self, Layout}; use iced::advanced::{layout, renderer};
use iced_native::renderer; use iced::advanced::widget::{Tree, Widget};
use iced_native::{Color, Element, Length, Point, Rectangle, Widget}; use iced::{Color, Element, Length, Point, Rectangle, alignment};
use iced_native::text; use iced::advanced::text::{self, Text, LineHeight, Shaping};
use iced_native::alignment;
use iced_native::widget::Tree;
use chrono::{NaiveDate, Datelike, Duration, Local}; use chrono::{NaiveDate, Datelike, Duration, Local};
use super::basics::CellGrid; use super::basics::CellGrid;
use crate::model::events::EventsCollection; use crate::model::events::EventsCollection;
@ -85,21 +83,102 @@ impl CalendarParams {
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
pub struct CalendarMonthView { fn render_events_in_day(
params: &CalendarParams,
renderer: &mut impl text::Renderer,
current_day: NaiveDate,
day_bounds: Rectangle,
font_size: f32,
fg: Color,
content: &str,
events: &EventsCollection
) {
// render events, if enough space
let day_text_size = renderer.measure(
content,
font_size,
LineHeight::default(),
renderer.default_font(),
day_bounds.size(),
Shaping::default());
let ev_height = params.ev_height;
let mut ev_y: f32 = 0.0;
let y = day_bounds.y + params.day_text_margin;
for ev_day in events.for_day(current_day) {
if day_bounds.height - day_text_size.1 > ev_y + ev_height {
let ev_bounds = Rectangle {
y: y + ev_y + day_text_size.1,
height: ev_height,
..day_bounds
};
renderer.fill_quad(renderer::Quad {
bounds: ev_bounds,
border_radius: 0.0.into(),
border_width: 1.0,
border_color: params.day_other_month_fg,
},
params.ev_bg);
renderer.fill_text(Text {
content: ev_day.text.as_str(),
bounds: ev_bounds,
size: params.ev_fontsize,
line_height: LineHeight::default(),
color: fg,
font: renderer.default_font(),
horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Top,
shaping: Shaping::default(),
});
ev_y += ev_height
}
}
if day_bounds.height - day_text_size.1 > ev_height {
if let Some(ev_day) = events.is_any_in_day(current_day) {
let ev_bounds = Rectangle {
y: y + day_text_size.1,
height: ev_height,
..day_bounds
};
renderer.fill_quad(renderer::Quad {
bounds: ev_bounds,
border_radius: 0.0.into(),
border_width: 1.0,
border_color: params.day_other_month_fg,
},
params.ev_bg);
renderer.fill_text(Text {
content: ev_day.text.as_str(),
bounds: ev_bounds,
size: params.ev_fontsize,
line_height: LineHeight::default(),
color: fg,
font: renderer.default_font(),
horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Top,
shaping: Shaping::default(),
});
}
}
}
//-------------------------------------------------------------------------
pub struct CalendarMonthView<'a> {
first_day: NaiveDate, first_day: NaiveDate,
first_day_in_view: NaiveDate, first_day_in_view: NaiveDate,
params: CalendarParams, params: CalendarParams,
week_column_width: f32, week_column_width: f32,
week_column_font_size: f32, week_column_font_size: f32,
events: &'a EventsCollection,
} }
impl CalendarMonthView { impl<'a> CalendarMonthView<'a> {
pub fn new(params: &CalendarParams, day: NaiveDate) -> Self { pub fn new(params: &CalendarParams, day: NaiveDate, events: &'a EventsCollection) -> Self {
// first day of the month // first day of the month
let first_day = if day.day() == 1 { let first_day = if day.day() == 1 {
day day
} else { } else {
NaiveDate::from_ymd(day.year(), day.month(), 1) NaiveDate::from_ymd_opt(day.year(), day.month(), 1).unwrap()
}; };
// weekday on first day of the month // weekday on first day of the month
@ -114,6 +193,7 @@ impl CalendarMonthView {
params: params.clone(), params: params.clone(),
week_column_width: 30.0, week_column_width: 30.0,
week_column_font_size: 18.0, week_column_font_size: 18.0,
events,
} }
} }
@ -122,7 +202,7 @@ impl CalendarMonthView {
let first_day = if day.day() == 1 { let first_day = if day.day() == 1 {
day day
} else { } else {
NaiveDate::from_ymd(day.year(), day.month(), 1) NaiveDate::from_ymd_opt(day.year(), day.month(), 1).unwrap()
}; };
// weekday on first day of the month // weekday on first day of the month
@ -178,14 +258,16 @@ impl CalendarMonthView {
// color of text // color of text
let fg = self.params.header_fg; let fg = self.params.header_fg;
renderer.fill_text(text::Text { renderer.fill_text(Text {
content : t, content : t,
size: font_size,
bounds, bounds,
size: font_size,
line_height: LineHeight::default(),
color: fg, color: fg,
font: Default::default(), font: renderer.default_font(),
horizontal_alignment: alignment::Horizontal::Left, horizontal_alignment: alignment::Horizontal::Right,
vertical_alignment: alignment::Vertical::Center, vertical_alignment: alignment::Vertical::Center,
shaping: Shaping::default(),
}); });
} }
} }
@ -211,18 +293,20 @@ impl CalendarMonthView {
day += Duration::weeks(1); day += Duration::weeks(1);
// render week cell text // render week cell text
renderer.fill_text(text::Text { renderer.fill_text(Text {
content : &(week_of_first_day_of_month).to_string(), content : &(week_of_first_day_of_month).to_string(),
size: self.week_column_font_size,
bounds: Rectangle { bounds: Rectangle {
x: day_bounds.center_x(), x: day_bounds.center_x(),
y: day_bounds.y, y: day_bounds.y,
..day_bounds ..day_bounds
}, },
size: self.week_column_font_size,
line_height: LineHeight::default(),
color: self.params.day_fg, color: self.params.day_fg,
font: Default::default(), font: renderer.default_font(),
horizontal_alignment: alignment::Horizontal::Center, horizontal_alignment: alignment::Horizontal::Center,
vertical_alignment: alignment::Vertical::Top, vertical_alignment: alignment::Vertical::Top,
shaping: Shaping::default(),
}); });
} }
} }
@ -258,7 +342,7 @@ impl CalendarMonthView {
}; };
// background color of the day cell // background color of the day cell
let bg_color = if current_day == Local::today().naive_local() { let bg_color = if current_day == Local::now().date_naive() {
self.params.day_today_bg self.params.day_today_bg
} else if current_day.weekday().num_days_from_monday() > 4 { } else if current_day.weekday().num_days_from_monday() > 4 {
self.params.day_weekend_bg self.params.day_weekend_bg
@ -279,22 +363,36 @@ impl CalendarMonthView {
bg_color); bg_color);
// render day cell text // render day cell text
renderer.fill_text(text::Text { renderer.fill_text(Text {
content, content,
size: font_size,
bounds: Rectangle {x, y, ..day_bounds}, bounds: Rectangle {x, y, ..day_bounds},
size: font_size,
line_height: LineHeight::default(),
color: fg, color: fg,
font: Default::default(), font: renderer.default_font(),
horizontal_alignment: alignment::Horizontal::Left, horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Top, vertical_alignment: alignment::Vertical::Top,
shaping: Shaping::default()
}); });
current_day = current_day.succ();
render_events_in_day(
&self.params,
renderer,
current_day,
day_bounds,
font_size,
fg,
content,
self.events
);
current_day = current_day.succ_opt().unwrap();
} }
} }
} // CalendarMonthView } // CalendarMonthView
impl<Message, Renderer> Widget<Message, Renderer> for CalendarMonthView impl<Message, Renderer> Widget<Message, Renderer> for CalendarMonthView<'_>
where where
Renderer: text::Renderer, Renderer: text::Renderer,
{ {
@ -320,7 +418,7 @@ where
renderer: &mut Renderer, renderer: &mut Renderer,
_theme: &Renderer::Theme, _theme: &Renderer::Theme,
_style: &renderer::Style, _style: &renderer::Style,
layout: Layout<'_>, layout: layout::Layout<'_>,
_cursor_position: Point, _cursor_position: Point,
_viewport: &Rectangle, _viewport: &Rectangle,
) { ) {
@ -359,11 +457,11 @@ where
} }
} }
impl<'a, Message, Renderer> From<CalendarMonthView> for Element<'a, Message, Renderer> impl<'a, Message, Renderer> From<CalendarMonthView<'a>> for Element<'a, Message, Renderer>
where where
Renderer: text::Renderer, Renderer: text::Renderer,
{ {
fn from(month_view: CalendarMonthView) -> Self { fn from(month_view: CalendarMonthView<'a>) -> Self {
Self::new(month_view) Self::new(month_view)
} }
} }
@ -382,7 +480,7 @@ pub struct CalendarYearView<'a> {
impl<'a> CalendarYearView<'a> { impl<'a> CalendarYearView<'a> {
pub fn new(params: &CalendarParams, day: NaiveDate, events: &'a EventsCollection) -> Self { pub fn new(params: &CalendarParams, day: NaiveDate, events: &'a EventsCollection) -> Self {
// first day of the year // first day of the year
let first_day = NaiveDate::from_ymd(day.year(), 1, 1); let first_day = NaiveDate::from_ymd_opt(day.year(), 1, 1).unwrap();
// weekday on first day of the year // weekday on first day of the year
let weekday_on_first = first_day.weekday(); let weekday_on_first = first_day.weekday();
@ -402,7 +500,7 @@ impl<'a> CalendarYearView<'a> {
pub fn set_year(&mut self, day: NaiveDate) { pub fn set_year(&mut self, day: NaiveDate) {
// first day of the year // first day of the year
self.first_day = NaiveDate::from_ymd(day.year(), 1, 1); self.first_day = NaiveDate::from_ymd_opt(day.year(), 1, 1).unwrap();
// weekday on first day of the year // weekday on first day of the year
let weekday_on_first = self.first_day.weekday(); let weekday_on_first = self.first_day.weekday();
@ -474,14 +572,16 @@ impl<'a> CalendarYearView<'a> {
let x = bounds.x + self.params.day_text_margin; let x = bounds.x + self.params.day_text_margin;
let y = bounds.center_y(); let y = bounds.center_y();
renderer.fill_text(text::Text { renderer.fill_text(Text {
content : t, content : t,
size: font_size,
bounds: Rectangle {x, y, ..bounds}, bounds: Rectangle {x, y, ..bounds},
size: font_size,
line_height: LineHeight::default(),
color: fg, color: fg,
font: Default::default(), font: renderer.default_font(),
horizontal_alignment: alignment::Horizontal::Left, horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Center, vertical_alignment: alignment::Vertical::Center,
shaping: Shaping::default(),
}); });
} }
} }
@ -504,18 +604,20 @@ impl<'a> CalendarYearView<'a> {
}; };
// render month name // render month name
renderer.fill_text(text::Text { renderer.fill_text(Text {
content : MONTH_NAMES[month], content : MONTH_NAMES[month],
size: self.month_column_font_size,
bounds: Rectangle { bounds: Rectangle {
x: month_name_bounds.x + self.margin, x: month_name_bounds.x + self.margin,
y: month_name_bounds.center_y(), y: month_name_bounds.center_y(),
..month_name_bounds ..month_name_bounds
}, },
size: self.month_column_font_size,
line_height: LineHeight::default(),
color: self.params.day_fg, color: self.params.day_fg,
font: Default::default(), font: renderer.default_font(),
horizontal_alignment: alignment::Horizontal::Left, horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Center, vertical_alignment: alignment::Vertical::Center,
shaping: Shaping::default(),
}); });
} }
} }
@ -555,7 +657,7 @@ impl<'a> CalendarYearView<'a> {
let fg = self.params.day_fg; let fg = self.params.day_fg;
// background color of the day cell // background color of the day cell
let bg_color = if current_day == Local::today().naive_local() { let bg_color = if current_day == Local::now().date_naive() {
self.params.day_today_bg self.params.day_today_bg
} else if weekday > 4 { } else if weekday > 4 {
self.params.day_weekend_bg self.params.day_weekend_bg
@ -576,44 +678,28 @@ impl<'a> CalendarYearView<'a> {
bg_color); bg_color);
// render day cell text // render day cell text
renderer.fill_text(text::Text { renderer.fill_text(Text {
content, content,
size: font_size,
bounds: Rectangle {x, y, ..day_bounds}, bounds: Rectangle {x, y, ..day_bounds},
size: font_size,
line_height: LineHeight::default(),
color: fg, color: fg,
font: Default::default(), font: renderer.default_font(),
horizontal_alignment: alignment::Horizontal::Left, horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Top, vertical_alignment: alignment::Vertical::Top,
shaping: Shaping::default(),
}); });
// render events, if enough space render_events_in_day(
let day_text_size = renderer.measure(content, font_size, Default::default(), day_bounds.size()); &self.params,
let ev_height = self.params.ev_height; renderer,
if day_bounds.height - day_text_size.1 > ev_height { current_day,
if let Some(ev_day) = self.events.is_any_in_day(current_day) { day_bounds,
let ev_bounds = Rectangle { font_size,
y: y + day_text_size.1, fg,
height: ev_height, content,
..day_bounds self.events
}; );
renderer.fill_quad(renderer::Quad {
bounds: ev_bounds,
border_radius: 0.0.into(),
border_width: 1.0,
border_color: self.params.day_other_month_fg,
},
self.params.ev_bg);
renderer.fill_text(text::Text {
content: ev_day.text.as_str(),
size: self.params.ev_fontsize,
bounds: ev_bounds,
color: fg,
font: Default::default(),
horizontal_alignment: alignment::Horizontal::Left,
vertical_alignment: alignment::Vertical::Top,
});
}
}
} }
} }
} }
@ -621,7 +707,11 @@ impl<'a> CalendarYearView<'a> {
fn compute_month_col_width(&self, renderer: &mut impl text::Renderer) -> f32 { fn compute_month_col_width(&self, renderer: &mut impl text::Renderer) -> f32 {
let mut max_max_font_width = 0.0; let mut max_max_font_width = 0.0;
for month_name in MONTH_NAMES { for month_name in MONTH_NAMES {
let month_width = renderer.measure_width(month_name, self.month_column_font_size, Default::default()); let month_width = renderer.measure_width(
month_name,
self.month_column_font_size,
renderer.default_font(),
Shaping::default());
if month_width > max_max_font_width { if month_width > max_max_font_width {
max_max_font_width = month_width; max_max_font_width = month_width;
} }
@ -657,7 +747,7 @@ where
renderer: &mut Renderer, renderer: &mut Renderer,
_theme: &Renderer::Theme, _theme: &Renderer::Theme,
_style: &renderer::Style, _style: &renderer::Style,
layout: Layout<'_>, layout: layout::Layout<'_>,
_cursor_position: Point, _cursor_position: Point,
_viewport: &Rectangle, _viewport: &Rectangle,
) { ) {