use iced::widget::canvas::{self, Canvas, Frame, Geometry, Path, Stroke};
use iced::{mouse, Color, Element, Length, Point, Rectangle, Renderer, Theme};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum IconName {
Home,
Menu,
Close,
ArrowLeft,
ArrowRight,
ArrowUp,
ArrowDown,
ChevronLeft,
ChevronRight,
ChevronUp,
ChevronDown,
Plus,
Minus,
Check,
Search,
Settings,
Edit,
Trash,
Refresh,
Download,
Upload,
Share,
Copy,
Info,
Warning,
Error,
Success,
Play,
Pause,
Stop,
Record,
Volume,
Mute,
Microphone,
Camera,
File,
Folder,
Image,
Grid,
List,
Mail,
Chat,
Bell,
User,
Users,
Sun,
Moon,
Globe,
Link,
Star,
Heart,
Eye,
EyeOff,
Lock,
Unlock,
}
pub struct Icon {
name: IconName,
size: f32,
color: Option<Color>,
}
impl Icon {
#[must_use]
pub fn new(name: IconName) -> Self {
Self {
name,
size: 24.0,
color: None,
}
}
#[must_use]
pub fn size(mut self, size: f32) -> Self {
self.size = size;
self
}
#[must_use]
pub fn color(mut self, color: Color) -> Self {
self.color = Some(color);
self
}
#[must_use]
pub fn home() -> Self {
Self::new(IconName::Home)
}
#[must_use]
pub fn menu() -> Self {
Self::new(IconName::Menu)
}
#[must_use]
pub fn close() -> Self {
Self::new(IconName::Close)
}
#[must_use]
pub fn settings() -> Self {
Self::new(IconName::Settings)
}
#[must_use]
pub fn search() -> Self {
Self::new(IconName::Search)
}
#[must_use]
pub fn plus() -> Self {
Self::new(IconName::Plus)
}
#[must_use]
pub fn check() -> Self {
Self::new(IconName::Check)
}
#[must_use]
pub fn info() -> Self {
Self::new(IconName::Info)
}
#[must_use]
pub fn warning() -> Self {
Self::new(IconName::Warning)
}
#[must_use]
pub fn error() -> Self {
Self::new(IconName::Error)
}
#[must_use]
pub fn success() -> Self {
Self::new(IconName::Success)
}
#[must_use]
pub fn play() -> Self {
Self::new(IconName::Play)
}
#[must_use]
pub fn pause() -> Self {
Self::new(IconName::Pause)
}
#[must_use]
pub fn sun() -> Self {
Self::new(IconName::Sun)
}
#[must_use]
pub fn moon() -> Self {
Self::new(IconName::Moon)
}
#[must_use]
pub fn user() -> Self {
Self::new(IconName::User)
}
#[must_use]
pub fn globe() -> Self {
Self::new(IconName::Globe)
}
#[must_use]
pub fn grid() -> Self {
Self::new(IconName::Grid)
}
#[must_use]
pub fn edit() -> Self {
Self::new(IconName::Edit)
}
#[must_use]
pub fn chat() -> Self {
Self::new(IconName::Chat)
}
#[must_use]
pub fn camera() -> Self {
Self::new(IconName::Camera)
}
}
struct IconProgram {
name: IconName,
color: Option<Color>,
}
impl IconProgram {
fn draw_icon(&self, frame: &mut Frame, bounds: Rectangle, color: Color) {
let size = bounds.width.min(bounds.height);
let center = Point::new(bounds.width / 2.0, bounds.height / 2.0);
let stroke = Stroke::default().with_width(size * 0.08).with_color(color);
let thin_stroke = Stroke::default().with_width(size * 0.06).with_color(color);
match self.name {
IconName::Home => {
let roof = Path::new(|b| {
b.move_to(Point::new(center.x, size * 0.15));
b.line_to(Point::new(size * 0.85, size * 0.45));
b.line_to(Point::new(size * 0.15, size * 0.45));
b.close();
});
frame.fill(&roof, color);
let house = Path::new(|b| {
b.move_to(Point::new(size * 0.25, size * 0.45));
b.line_to(Point::new(size * 0.25, size * 0.85));
b.line_to(Point::new(size * 0.75, size * 0.85));
b.line_to(Point::new(size * 0.75, size * 0.45));
});
frame.stroke(&house, stroke);
}
IconName::Menu => {
for i in 0..3 {
let y = size * (0.3 + i as f32 * 0.2);
let line = Path::line(
Point::new(size * 0.2, y),
Point::new(size * 0.8, y),
);
frame.stroke(&line, stroke);
}
}
IconName::Close => {
let line1 = Path::line(
Point::new(size * 0.25, size * 0.25),
Point::new(size * 0.75, size * 0.75),
);
let line2 = Path::line(
Point::new(size * 0.75, size * 0.25),
Point::new(size * 0.25, size * 0.75),
);
frame.stroke(&line1, stroke);
frame.stroke(&line2, stroke);
}
IconName::ArrowLeft => {
let arrow = Path::new(|b| {
b.move_to(Point::new(size * 0.6, size * 0.25));
b.line_to(Point::new(size * 0.3, size * 0.5));
b.line_to(Point::new(size * 0.6, size * 0.75));
});
frame.stroke(&arrow, stroke);
let line = Path::line(
Point::new(size * 0.3, size * 0.5),
Point::new(size * 0.8, size * 0.5),
);
frame.stroke(&line, stroke);
}
IconName::ArrowRight => {
let arrow = Path::new(|b| {
b.move_to(Point::new(size * 0.4, size * 0.25));
b.line_to(Point::new(size * 0.7, size * 0.5));
b.line_to(Point::new(size * 0.4, size * 0.75));
});
frame.stroke(&arrow, stroke);
let line = Path::line(
Point::new(size * 0.2, size * 0.5),
Point::new(size * 0.7, size * 0.5),
);
frame.stroke(&line, stroke);
}
IconName::ArrowUp => {
let arrow = Path::new(|b| {
b.move_to(Point::new(size * 0.25, size * 0.6));
b.line_to(Point::new(size * 0.5, size * 0.3));
b.line_to(Point::new(size * 0.75, size * 0.6));
});
frame.stroke(&arrow, stroke);
let line = Path::line(
Point::new(size * 0.5, size * 0.3),
Point::new(size * 0.5, size * 0.8),
);
frame.stroke(&line, stroke);
}
IconName::ArrowDown => {
let arrow = Path::new(|b| {
b.move_to(Point::new(size * 0.25, size * 0.4));
b.line_to(Point::new(size * 0.5, size * 0.7));
b.line_to(Point::new(size * 0.75, size * 0.4));
});
frame.stroke(&arrow, stroke);
let line = Path::line(
Point::new(size * 0.5, size * 0.2),
Point::new(size * 0.5, size * 0.7),
);
frame.stroke(&line, stroke);
}
IconName::ChevronLeft => {
let chevron = Path::new(|b| {
b.move_to(Point::new(size * 0.6, size * 0.2));
b.line_to(Point::new(size * 0.35, size * 0.5));
b.line_to(Point::new(size * 0.6, size * 0.8));
});
frame.stroke(&chevron, stroke);
}
IconName::ChevronRight => {
let chevron = Path::new(|b| {
b.move_to(Point::new(size * 0.4, size * 0.2));
b.line_to(Point::new(size * 0.65, size * 0.5));
b.line_to(Point::new(size * 0.4, size * 0.8));
});
frame.stroke(&chevron, stroke);
}
IconName::ChevronUp => {
let chevron = Path::new(|b| {
b.move_to(Point::new(size * 0.2, size * 0.6));
b.line_to(Point::new(size * 0.5, size * 0.35));
b.line_to(Point::new(size * 0.8, size * 0.6));
});
frame.stroke(&chevron, stroke);
}
IconName::ChevronDown => {
let chevron = Path::new(|b| {
b.move_to(Point::new(size * 0.2, size * 0.4));
b.line_to(Point::new(size * 0.5, size * 0.65));
b.line_to(Point::new(size * 0.8, size * 0.4));
});
frame.stroke(&chevron, stroke);
}
IconName::Plus => {
let h = Path::line(
Point::new(size * 0.2, size * 0.5),
Point::new(size * 0.8, size * 0.5),
);
let v = Path::line(
Point::new(size * 0.5, size * 0.2),
Point::new(size * 0.5, size * 0.8),
);
frame.stroke(&h, stroke);
frame.stroke(&v, stroke);
}
IconName::Minus => {
let line = Path::line(
Point::new(size * 0.2, size * 0.5),
Point::new(size * 0.8, size * 0.5),
);
frame.stroke(&line, stroke);
}
IconName::Check => {
let check = Path::new(|b| {
b.move_to(Point::new(size * 0.2, size * 0.5));
b.line_to(Point::new(size * 0.4, size * 0.7));
b.line_to(Point::new(size * 0.8, size * 0.3));
});
frame.stroke(&check, stroke);
}
IconName::Search => {
let circle = Path::circle(Point::new(size * 0.42, size * 0.42), size * 0.25);
frame.stroke(&circle, stroke);
let handle = Path::line(
Point::new(size * 0.6, size * 0.6),
Point::new(size * 0.85, size * 0.85),
);
frame.stroke(&handle, stroke);
}
IconName::Settings => {
let circle = Path::circle(center, size * 0.2);
frame.stroke(&circle, stroke);
for i in 0..6 {
let angle = i as f32 * std::f32::consts::PI / 3.0;
let inner = size * 0.28;
let outer = size * 0.42;
let line = Path::line(
Point::new(
center.x + angle.cos() * inner,
center.y + angle.sin() * inner,
),
Point::new(
center.x + angle.cos() * outer,
center.y + angle.sin() * outer,
),
);
frame.stroke(&line, stroke);
}
}
IconName::Edit => {
let pencil = Path::new(|b| {
b.move_to(Point::new(size * 0.7, size * 0.2));
b.line_to(Point::new(size * 0.8, size * 0.3));
b.line_to(Point::new(size * 0.35, size * 0.75));
b.line_to(Point::new(size * 0.2, size * 0.8));
b.line_to(Point::new(size * 0.25, size * 0.65));
b.close();
});
frame.stroke(&pencil, thin_stroke);
}
IconName::Trash => {
let lid = Path::line(
Point::new(size * 0.2, size * 0.3),
Point::new(size * 0.8, size * 0.3),
);
frame.stroke(&lid, stroke);
let can = Path::new(|b| {
b.move_to(Point::new(size * 0.25, size * 0.3));
b.line_to(Point::new(size * 0.3, size * 0.85));
b.line_to(Point::new(size * 0.7, size * 0.85));
b.line_to(Point::new(size * 0.75, size * 0.3));
});
frame.stroke(&can, thin_stroke);
let handle = Path::new(|b| {
b.move_to(Point::new(size * 0.4, size * 0.3));
b.line_to(Point::new(size * 0.4, size * 0.2));
b.line_to(Point::new(size * 0.6, size * 0.2));
b.line_to(Point::new(size * 0.6, size * 0.3));
});
frame.stroke(&handle, thin_stroke);
}
IconName::Refresh => {
let arc = Path::new(|b| {
b.arc(canvas::path::Arc {
center,
radius: size * 0.3,
start_angle: iced::Radians(-0.5),
end_angle: iced::Radians(std::f32::consts::PI + 0.5),
});
});
frame.stroke(&arc, stroke);
let arrow = Path::new(|b| {
b.move_to(Point::new(size * 0.65, size * 0.2));
b.line_to(Point::new(size * 0.8, size * 0.35));
b.line_to(Point::new(size * 0.65, size * 0.35));
});
frame.fill(&arrow, color);
}
IconName::Download => {
let arrow = Path::new(|b| {
b.move_to(Point::new(size * 0.5, size * 0.15));
b.line_to(Point::new(size * 0.5, size * 0.6));
});
frame.stroke(&arrow, stroke);
let head = Path::new(|b| {
b.move_to(Point::new(size * 0.3, size * 0.45));
b.line_to(Point::new(size * 0.5, size * 0.65));
b.line_to(Point::new(size * 0.7, size * 0.45));
});
frame.stroke(&head, stroke);
let base = Path::line(
Point::new(size * 0.2, size * 0.85),
Point::new(size * 0.8, size * 0.85),
);
frame.stroke(&base, stroke);
}
IconName::Upload => {
let arrow = Path::new(|b| {
b.move_to(Point::new(size * 0.5, size * 0.6));
b.line_to(Point::new(size * 0.5, size * 0.15));
});
frame.stroke(&arrow, stroke);
let head = Path::new(|b| {
b.move_to(Point::new(size * 0.3, size * 0.35));
b.line_to(Point::new(size * 0.5, size * 0.15));
b.line_to(Point::new(size * 0.7, size * 0.35));
});
frame.stroke(&head, stroke);
let base = Path::line(
Point::new(size * 0.2, size * 0.85),
Point::new(size * 0.8, size * 0.85),
);
frame.stroke(&base, stroke);
}
IconName::Share => {
let top = Path::circle(Point::new(size * 0.7, size * 0.25), size * 0.1);
let mid = Path::circle(Point::new(size * 0.3, size * 0.5), size * 0.1);
let bot = Path::circle(Point::new(size * 0.7, size * 0.75), size * 0.1);
frame.fill(&top, color);
frame.fill(&mid, color);
frame.fill(&bot, color);
let line1 = Path::line(
Point::new(size * 0.38, size * 0.45),
Point::new(size * 0.62, size * 0.3),
);
let line2 = Path::line(
Point::new(size * 0.38, size * 0.55),
Point::new(size * 0.62, size * 0.7),
);
frame.stroke(&line1, thin_stroke);
frame.stroke(&line2, thin_stroke);
}
IconName::Copy => {
let back = Path::new(|b| {
b.move_to(Point::new(size * 0.3, size * 0.2));
b.line_to(Point::new(size * 0.75, size * 0.2));
b.line_to(Point::new(size * 0.75, size * 0.65));
b.line_to(Point::new(size * 0.3, size * 0.65));
b.close();
});
frame.stroke(&back, thin_stroke);
let front = Path::new(|b| {
b.move_to(Point::new(size * 0.25, size * 0.35));
b.line_to(Point::new(size * 0.7, size * 0.35));
b.line_to(Point::new(size * 0.7, size * 0.8));
b.line_to(Point::new(size * 0.25, size * 0.8));
b.close();
});
frame.stroke(&front, thin_stroke);
}
IconName::Info => {
let circle = Path::circle(center, size * 0.4);
frame.stroke(&circle, thin_stroke);
let dot = Path::circle(Point::new(center.x, size * 0.3), size * 0.05);
frame.fill(&dot, color);
let stem = Path::line(
Point::new(center.x, size * 0.45),
Point::new(center.x, size * 0.75),
);
frame.stroke(&stem, stroke);
}
IconName::Warning => {
let triangle = Path::new(|b| {
b.move_to(Point::new(size * 0.5, size * 0.15));
b.line_to(Point::new(size * 0.9, size * 0.85));
b.line_to(Point::new(size * 0.1, size * 0.85));
b.close();
});
frame.stroke(&triangle, thin_stroke);
let line = Path::line(
Point::new(center.x, size * 0.35),
Point::new(center.x, size * 0.6),
);
frame.stroke(&line, stroke);
let dot = Path::circle(Point::new(center.x, size * 0.72), size * 0.04);
frame.fill(&dot, color);
}
IconName::Error => {
let circle = Path::circle(center, size * 0.4);
frame.stroke(&circle, thin_stroke);
let line1 = Path::line(
Point::new(size * 0.35, size * 0.35),
Point::new(size * 0.65, size * 0.65),
);
let line2 = Path::line(
Point::new(size * 0.65, size * 0.35),
Point::new(size * 0.35, size * 0.65),
);
frame.stroke(&line1, stroke);
frame.stroke(&line2, stroke);
}
IconName::Success => {
let circle = Path::circle(center, size * 0.4);
frame.stroke(&circle, thin_stroke);
let check = Path::new(|b| {
b.move_to(Point::new(size * 0.3, size * 0.5));
b.line_to(Point::new(size * 0.45, size * 0.65));
b.line_to(Point::new(size * 0.7, size * 0.35));
});
frame.stroke(&check, stroke);
}
IconName::Play => {
let triangle = Path::new(|b| {
b.move_to(Point::new(size * 0.3, size * 0.2));
b.line_to(Point::new(size * 0.8, size * 0.5));
b.line_to(Point::new(size * 0.3, size * 0.8));
b.close();
});
frame.fill(&triangle, color);
}
IconName::Pause => {
let left = Path::new(|b| {
b.move_to(Point::new(size * 0.3, size * 0.2));
b.line_to(Point::new(size * 0.42, size * 0.2));
b.line_to(Point::new(size * 0.42, size * 0.8));
b.line_to(Point::new(size * 0.3, size * 0.8));
b.close();
});
let right = Path::new(|b| {
b.move_to(Point::new(size * 0.58, size * 0.2));
b.line_to(Point::new(size * 0.7, size * 0.2));
b.line_to(Point::new(size * 0.7, size * 0.8));
b.line_to(Point::new(size * 0.58, size * 0.8));
b.close();
});
frame.fill(&left, color);
frame.fill(&right, color);
}
IconName::Stop => {
let square = Path::new(|b| {
b.move_to(Point::new(size * 0.25, size * 0.25));
b.line_to(Point::new(size * 0.75, size * 0.25));
b.line_to(Point::new(size * 0.75, size * 0.75));
b.line_to(Point::new(size * 0.25, size * 0.75));
b.close();
});
frame.fill(&square, color);
}
IconName::Record => {
let circle = Path::circle(center, size * 0.35);
frame.fill(&circle, color);
}
IconName::Volume => {
let speaker = Path::new(|b| {
b.move_to(Point::new(size * 0.2, size * 0.4));
b.line_to(Point::new(size * 0.35, size * 0.4));
b.line_to(Point::new(size * 0.5, size * 0.25));
b.line_to(Point::new(size * 0.5, size * 0.75));
b.line_to(Point::new(size * 0.35, size * 0.6));
b.line_to(Point::new(size * 0.2, size * 0.6));
b.close();
});
frame.fill(&speaker, color);
let wave1 = Path::new(|b| {
b.arc(canvas::path::Arc {
center: Point::new(size * 0.5, size * 0.5),
radius: size * 0.15,
start_angle: iced::Radians(-0.8),
end_angle: iced::Radians(0.8),
});
});
let wave2 = Path::new(|b| {
b.arc(canvas::path::Arc {
center: Point::new(size * 0.5, size * 0.5),
radius: size * 0.28,
start_angle: iced::Radians(-0.8),
end_angle: iced::Radians(0.8),
});
});
frame.stroke(&wave1, thin_stroke);
frame.stroke(&wave2, thin_stroke);
}
IconName::Mute => {
let speaker = Path::new(|b| {
b.move_to(Point::new(size * 0.15, size * 0.4));
b.line_to(Point::new(size * 0.3, size * 0.4));
b.line_to(Point::new(size * 0.45, size * 0.25));
b.line_to(Point::new(size * 0.45, size * 0.75));
b.line_to(Point::new(size * 0.3, size * 0.6));
b.line_to(Point::new(size * 0.15, size * 0.6));
b.close();
});
frame.fill(&speaker, color);
let line1 = Path::line(
Point::new(size * 0.55, size * 0.35),
Point::new(size * 0.85, size * 0.65),
);
let line2 = Path::line(
Point::new(size * 0.85, size * 0.35),
Point::new(size * 0.55, size * 0.65),
);
frame.stroke(&line1, stroke);
frame.stroke(&line2, stroke);
}
IconName::Microphone => {
let mic = Path::new(|b| {
b.move_to(Point::new(size * 0.35, size * 0.15));
b.line_to(Point::new(size * 0.65, size * 0.15));
b.line_to(Point::new(size * 0.65, size * 0.5));
b.arc(canvas::path::Arc {
center: Point::new(size * 0.5, size * 0.5),
radius: size * 0.15,
start_angle: iced::Radians(0.0),
end_angle: iced::Radians(std::f32::consts::PI),
});
b.line_to(Point::new(size * 0.35, size * 0.15));
});
frame.stroke(&mic, thin_stroke);
let stand = Path::new(|b| {
b.arc(canvas::path::Arc {
center: Point::new(size * 0.5, size * 0.5),
radius: size * 0.28,
start_angle: iced::Radians(0.3),
end_angle: iced::Radians(std::f32::consts::PI - 0.3),
});
});
frame.stroke(&stand, thin_stroke);
let stem = Path::line(
Point::new(size * 0.5, size * 0.78),
Point::new(size * 0.5, size * 0.9),
);
frame.stroke(&stem, thin_stroke);
}
IconName::Camera => {
let body = Path::new(|b| {
b.move_to(Point::new(size * 0.1, size * 0.35));
b.line_to(Point::new(size * 0.3, size * 0.35));
b.line_to(Point::new(size * 0.38, size * 0.22));
b.line_to(Point::new(size * 0.62, size * 0.22));
b.line_to(Point::new(size * 0.7, size * 0.35));
b.line_to(Point::new(size * 0.9, size * 0.35));
b.line_to(Point::new(size * 0.9, size * 0.78));
b.line_to(Point::new(size * 0.1, size * 0.78));
b.close();
});
frame.stroke(&body, thin_stroke);
let lens = Path::circle(Point::new(size * 0.5, size * 0.55), size * 0.15);
frame.stroke(&lens, thin_stroke);
}
IconName::File => {
let file = Path::new(|b| {
b.move_to(Point::new(size * 0.25, size * 0.1));
b.line_to(Point::new(size * 0.6, size * 0.1));
b.line_to(Point::new(size * 0.75, size * 0.25));
b.line_to(Point::new(size * 0.75, size * 0.9));
b.line_to(Point::new(size * 0.25, size * 0.9));
b.close();
});
frame.stroke(&file, thin_stroke);
let fold = Path::new(|b| {
b.move_to(Point::new(size * 0.6, size * 0.1));
b.line_to(Point::new(size * 0.6, size * 0.25));
b.line_to(Point::new(size * 0.75, size * 0.25));
});
frame.stroke(&fold, thin_stroke);
}
IconName::Folder => {
let folder = Path::new(|b| {
b.move_to(Point::new(size * 0.1, size * 0.25));
b.line_to(Point::new(size * 0.35, size * 0.25));
b.line_to(Point::new(size * 0.42, size * 0.35));
b.line_to(Point::new(size * 0.9, size * 0.35));
b.line_to(Point::new(size * 0.9, size * 0.8));
b.line_to(Point::new(size * 0.1, size * 0.8));
b.close();
});
frame.stroke(&folder, thin_stroke);
}
IconName::Image => {
let frame_path = Path::new(|b| {
b.move_to(Point::new(size * 0.15, size * 0.2));
b.line_to(Point::new(size * 0.85, size * 0.2));
b.line_to(Point::new(size * 0.85, size * 0.8));
b.line_to(Point::new(size * 0.15, size * 0.8));
b.close();
});
frame.stroke(&frame_path, thin_stroke);
let mountain = Path::new(|b| {
b.move_to(Point::new(size * 0.15, size * 0.7));
b.line_to(Point::new(size * 0.4, size * 0.45));
b.line_to(Point::new(size * 0.55, size * 0.55));
b.line_to(Point::new(size * 0.75, size * 0.35));
b.line_to(Point::new(size * 0.85, size * 0.55));
});
frame.stroke(&mountain, thin_stroke);
let sun = Path::circle(Point::new(size * 0.7, size * 0.35), size * 0.07);
frame.fill(&sun, color);
}
IconName::Grid => {
for row in 0..2 {
for col in 0..2 {
let x = size * (0.2 + col as f32 * 0.35);
let y = size * (0.2 + row as f32 * 0.35);
let rect = Path::new(|b| {
b.move_to(Point::new(x, y));
b.line_to(Point::new(x + size * 0.25, y));
b.line_to(Point::new(x + size * 0.25, y + size * 0.25));
b.line_to(Point::new(x, y + size * 0.25));
b.close();
});
frame.stroke(&rect, thin_stroke);
}
}
}
IconName::List => {
for i in 0..3 {
let y = size * (0.3 + i as f32 * 0.2);
let bullet = Path::circle(Point::new(size * 0.25, y), size * 0.04);
frame.fill(&bullet, color);
let line = Path::line(
Point::new(size * 0.35, y),
Point::new(size * 0.8, y),
);
frame.stroke(&line, thin_stroke);
}
}
IconName::Mail => {
let envelope = Path::new(|b| {
b.move_to(Point::new(size * 0.1, size * 0.25));
b.line_to(Point::new(size * 0.9, size * 0.25));
b.line_to(Point::new(size * 0.9, size * 0.75));
b.line_to(Point::new(size * 0.1, size * 0.75));
b.close();
});
frame.stroke(&envelope, thin_stroke);
let flap = Path::new(|b| {
b.move_to(Point::new(size * 0.1, size * 0.25));
b.line_to(Point::new(size * 0.5, size * 0.5));
b.line_to(Point::new(size * 0.9, size * 0.25));
});
frame.stroke(&flap, thin_stroke);
}
IconName::Chat => {
let bubble = Path::new(|b| {
b.move_to(Point::new(size * 0.15, size * 0.2));
b.line_to(Point::new(size * 0.85, size * 0.2));
b.line_to(Point::new(size * 0.85, size * 0.6));
b.line_to(Point::new(size * 0.4, size * 0.6));
b.line_to(Point::new(size * 0.25, size * 0.8));
b.line_to(Point::new(size * 0.25, size * 0.6));
b.line_to(Point::new(size * 0.15, size * 0.6));
b.close();
});
frame.stroke(&bubble, thin_stroke);
}
IconName::Bell => {
let bell = Path::new(|b| {
b.move_to(Point::new(size * 0.5, size * 0.12));
b.line_to(Point::new(size * 0.5, size * 0.2));
b.arc(canvas::path::Arc {
center: Point::new(size * 0.5, size * 0.45),
radius: size * 0.25,
start_angle: iced::Radians(-std::f32::consts::PI),
end_angle: iced::Radians(0.0),
});
b.line_to(Point::new(size * 0.85, size * 0.7));
b.line_to(Point::new(size * 0.15, size * 0.7));
b.line_to(Point::new(size * 0.25, size * 0.45));
});
frame.stroke(&bell, thin_stroke);
let clapper = Path::circle(Point::new(size * 0.5, size * 0.82), size * 0.07);
frame.fill(&clapper, color);
}
IconName::User => {
let head = Path::circle(Point::new(size * 0.5, size * 0.32), size * 0.18);
frame.stroke(&head, thin_stroke);
let body = Path::new(|b| {
b.arc(canvas::path::Arc {
center: Point::new(size * 0.5, size * 0.95),
radius: size * 0.35,
start_angle: iced::Radians(-std::f32::consts::PI),
end_angle: iced::Radians(0.0),
});
});
frame.stroke(&body, thin_stroke);
}
IconName::Users => {
let head1 = Path::circle(Point::new(size * 0.35, size * 0.32), size * 0.12);
frame.stroke(&head1, thin_stroke);
let head2 = Path::circle(Point::new(size * 0.6, size * 0.35), size * 0.15);
frame.stroke(&head2, thin_stroke);
let body2 = Path::new(|b| {
b.arc(canvas::path::Arc {
center: Point::new(size * 0.6, size * 0.95),
radius: size * 0.28,
start_angle: iced::Radians(-std::f32::consts::PI),
end_angle: iced::Radians(0.0),
});
});
frame.stroke(&body2, thin_stroke);
}
IconName::Sun => {
let circle = Path::circle(center, size * 0.18);
frame.fill(&circle, color);
for i in 0..8 {
let angle = i as f32 * std::f32::consts::PI / 4.0;
let inner = size * 0.28;
let outer = size * 0.42;
let line = Path::line(
Point::new(
center.x + angle.cos() * inner,
center.y + angle.sin() * inner,
),
Point::new(
center.x + angle.cos() * outer,
center.y + angle.sin() * outer,
),
);
frame.stroke(&line, stroke);
}
}
IconName::Moon => {
let crescent = Path::new(|b| {
b.arc(canvas::path::Arc {
center,
radius: size * 0.35,
start_angle: iced::Radians(-2.3),
end_angle: iced::Radians(2.3),
});
b.arc(canvas::path::Arc {
center: Point::new(center.x + size * 0.12, center.y),
radius: size * 0.28,
start_angle: iced::Radians(2.3),
end_angle: iced::Radians(-2.3),
});
});
frame.fill(&crescent, color);
}
IconName::Globe => {
let circle = Path::circle(center, size * 0.38);
frame.stroke(&circle, thin_stroke);
let h = Path::line(
Point::new(size * 0.12, size * 0.5),
Point::new(size * 0.88, size * 0.5),
);
frame.stroke(&h, thin_stroke);
let v = Path::new(|b| {
b.arc(canvas::path::Arc {
center,
radius: size * 0.2,
start_angle: iced::Radians(0.0),
end_angle: iced::Radians(std::f32::consts::PI * 2.0),
});
});
frame.stroke(&v, thin_stroke);
}
IconName::Link => {
let link1 = Path::new(|b| {
b.move_to(Point::new(size * 0.45, size * 0.35));
b.line_to(Point::new(size * 0.3, size * 0.35));
b.arc(canvas::path::Arc {
center: Point::new(size * 0.3, size * 0.5),
radius: size * 0.15,
start_angle: iced::Radians(-std::f32::consts::PI / 2.0),
end_angle: iced::Radians(std::f32::consts::PI / 2.0),
});
b.line_to(Point::new(size * 0.45, size * 0.65));
});
frame.stroke(&link1, stroke);
let link2 = Path::new(|b| {
b.move_to(Point::new(size * 0.55, size * 0.35));
b.line_to(Point::new(size * 0.7, size * 0.35));
b.arc(canvas::path::Arc {
center: Point::new(size * 0.7, size * 0.5),
radius: size * 0.15,
start_angle: iced::Radians(-std::f32::consts::PI / 2.0),
end_angle: iced::Radians(-std::f32::consts::PI * 1.5),
});
b.line_to(Point::new(size * 0.55, size * 0.65));
});
frame.stroke(&link2, stroke);
}
IconName::Star => {
let star = Path::new(|b| {
let points = 5;
let outer_r = size * 0.4;
let inner_r = size * 0.18;
for i in 0..points * 2 {
let r = if i % 2 == 0 { outer_r } else { inner_r };
let angle = (i as f32 * std::f32::consts::PI / points as f32)
- std::f32::consts::PI / 2.0;
let point = Point::new(
center.x + angle.cos() * r,
center.y + angle.sin() * r,
);
if i == 0 {
b.move_to(point);
} else {
b.line_to(point);
}
}
b.close();
});
frame.stroke(&star, thin_stroke);
}
IconName::Heart => {
let heart = Path::new(|b| {
b.move_to(Point::new(size * 0.5, size * 0.35));
b.bezier_curve_to(
Point::new(size * 0.5, size * 0.25),
Point::new(size * 0.3, size * 0.2),
Point::new(size * 0.2, size * 0.35),
);
b.bezier_curve_to(
Point::new(size * 0.1, size * 0.5),
Point::new(size * 0.2, size * 0.65),
Point::new(size * 0.5, size * 0.85),
);
b.bezier_curve_to(
Point::new(size * 0.8, size * 0.65),
Point::new(size * 0.9, size * 0.5),
Point::new(size * 0.8, size * 0.35),
);
b.bezier_curve_to(
Point::new(size * 0.7, size * 0.2),
Point::new(size * 0.5, size * 0.25),
Point::new(size * 0.5, size * 0.35),
);
});
frame.stroke(&heart, thin_stroke);
}
IconName::Eye => {
let eye = Path::new(|b| {
b.move_to(Point::new(size * 0.1, size * 0.5));
b.bezier_curve_to(
Point::new(size * 0.25, size * 0.25),
Point::new(size * 0.75, size * 0.25),
Point::new(size * 0.9, size * 0.5),
);
b.bezier_curve_to(
Point::new(size * 0.75, size * 0.75),
Point::new(size * 0.25, size * 0.75),
Point::new(size * 0.1, size * 0.5),
);
});
frame.stroke(&eye, thin_stroke);
let pupil = Path::circle(center, size * 0.12);
frame.fill(&pupil, color);
}
IconName::EyeOff => {
let eye = Path::new(|b| {
b.move_to(Point::new(size * 0.1, size * 0.5));
b.bezier_curve_to(
Point::new(size * 0.25, size * 0.25),
Point::new(size * 0.75, size * 0.25),
Point::new(size * 0.9, size * 0.5),
);
b.bezier_curve_to(
Point::new(size * 0.75, size * 0.75),
Point::new(size * 0.25, size * 0.75),
Point::new(size * 0.1, size * 0.5),
);
});
frame.stroke(&eye, thin_stroke);
let slash = Path::line(
Point::new(size * 0.2, size * 0.8),
Point::new(size * 0.8, size * 0.2),
);
frame.stroke(&slash, stroke);
}
IconName::Lock => {
let body = Path::new(|b| {
b.move_to(Point::new(size * 0.25, size * 0.45));
b.line_to(Point::new(size * 0.75, size * 0.45));
b.line_to(Point::new(size * 0.75, size * 0.85));
b.line_to(Point::new(size * 0.25, size * 0.85));
b.close();
});
frame.stroke(&body, thin_stroke);
let shackle = Path::new(|b| {
b.move_to(Point::new(size * 0.35, size * 0.45));
b.line_to(Point::new(size * 0.35, size * 0.32));
b.arc(canvas::path::Arc {
center: Point::new(size * 0.5, size * 0.32),
radius: size * 0.15,
start_angle: iced::Radians(std::f32::consts::PI),
end_angle: iced::Radians(0.0),
});
b.line_to(Point::new(size * 0.65, size * 0.45));
});
frame.stroke(&shackle, thin_stroke);
}
IconName::Unlock => {
let body = Path::new(|b| {
b.move_to(Point::new(size * 0.25, size * 0.45));
b.line_to(Point::new(size * 0.75, size * 0.45));
b.line_to(Point::new(size * 0.75, size * 0.85));
b.line_to(Point::new(size * 0.25, size * 0.85));
b.close();
});
frame.stroke(&body, thin_stroke);
let shackle = Path::new(|b| {
b.move_to(Point::new(size * 0.35, size * 0.45));
b.line_to(Point::new(size * 0.35, size * 0.32));
b.arc(canvas::path::Arc {
center: Point::new(size * 0.5, size * 0.32),
radius: size * 0.15,
start_angle: iced::Radians(std::f32::consts::PI),
end_angle: iced::Radians(0.2),
});
});
frame.stroke(&shackle, thin_stroke);
}
}
}
}
impl<Message> canvas::Program<Message, Theme> for IconProgram {
type State = ();
fn draw(
&self,
_state: &Self::State,
renderer: &Renderer,
theme: &Theme,
bounds: Rectangle,
_cursor: mouse::Cursor,
) -> Vec<Geometry> {
let mut frame = Frame::new(renderer, bounds.size());
let color = self.color.unwrap_or_else(|| {
theme.extended_palette().background.base.text
});
self.draw_icon(&mut frame, bounds, color);
vec![frame.into_geometry()]
}
}
impl<'a, Message: 'a> From<Icon> for Element<'a, Message, Theme> {
fn from(icon: Icon) -> Self {
let size = icon.size;
let program = IconProgram {
name: icon.name,
color: icon.color,
};
Canvas::new(program)
.width(Length::Fixed(size))
.height(Length::Fixed(size))
.into()
}
}
pub fn icon<'a, Message: 'a>(name: IconName, size: f32) -> Element<'a, Message, Theme> {
Icon::new(name).size(size).into()
}
pub fn icon_colored<'a, Message: 'a>(
name: IconName,
size: f32,
color: Color,
) -> Element<'a, Message, Theme> {
Icon::new(name).size(size).color(color).into()
}