ferrix_app/
widgets.rs

1/* widgets.rs
2 *
3 * Copyright 2025 Michail Krasnov <mskrasnov07@ya.ru>
4 *
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 *
18 * SPDX-License-Identifier: GPL-3.0-or-later
19 */
20
21//! Custom widgets for UI
22
23use iced::widget::svg::Handle;
24use iced::widget::text::IntoFragment;
25use iced::widget::tooltip;
26use iced::{
27    Color,
28    widget::{button, container, svg, text, tooltip::Position},
29};
30
31use crate::{
32    icons::{ABOUT_ICON, ERROR_ICON, EXPORT_ICON, SETTINGS_ICON},
33    messages::{ButtonsMessage, Message},
34    pages::Page,
35};
36
37pub fn icon_tooltip<'a, T>(icon_name: &'a str, tooltip: T) -> container::Container<'a, Message>
38where
39    T: IntoFragment<'a>,
40{
41    let svg_bytes = match icon_name {
42        "about" => ABOUT_ICON,
43        "error" => ERROR_ICON,
44        "export" => EXPORT_ICON,
45        "settings" => SETTINGS_ICON,
46        _ => &[],
47    };
48    let icon = svg(Handle::from_memory(svg_bytes))
49        .style(|theme: &iced::Theme, _| svg::Style {
50            color: Some(theme.palette().text),
51        })
52        .width(16)
53        .height(16);
54
55    container(iced::widget::tooltip(
56        icon,
57        container(text(tooltip).style(|s: &iced::Theme| text::Style {
58            color: Some(if s.extended_palette().is_dark {
59                s.palette().text
60            } else {
61                Color::WHITE
62            }),
63        }))
64        .padding(2)
65        .style(|_| container::Style {
66            background: Some(iced::Background::Color(Color::from_rgba8(0, 0, 0, 0.71))),
67            border: iced::Border {
68                radius: iced::border::Radius::from(2),
69                ..iced::Border::default()
70            },
71            ..Default::default()
72        }),
73        Position::Bottom,
74    ))
75    .width(16)
76    .height(16)
77}
78
79pub fn icon_button<'a>(icon_name: &'a str, tooltip: String) -> button::Button<'a, Message> {
80    let svg_bytes = match icon_name {
81        "about" => ABOUT_ICON,
82        "error" => ERROR_ICON,
83        "export" => EXPORT_ICON,
84        "settings" => SETTINGS_ICON,
85        _ => &[],
86    };
87    let icon = svg(Handle::from_memory(svg_bytes)).style(|theme: &iced::Theme, _| svg::Style {
88        color: Some(theme.palette().text),
89    });
90
91    button(iced::widget::tooltip(
92        icon.width(16).height(16),
93        container(text(tooltip).size(11).style(|s: &iced::Theme| text::Style {
94            color: Some(if s.extended_palette().is_dark {
95                s.palette().text
96            } else {
97                Color::WHITE
98            }),
99        }))
100        .padding(2)
101        .style(|_| container::Style {
102            background: Some(iced::Background::Color(Color::from_rgba8(0, 0, 0, 0.71))),
103            border: iced::Border {
104                radius: iced::border::Radius::from(2),
105                ..iced::Border::default()
106            },
107            ..Default::default()
108        }),
109        Position::Bottom,
110    ))
111    .style(button::subtle)
112    .padding(2)
113}
114
115pub fn sidebar_button<'a>(page: Page, cur_page: Page) -> button::Button<'a, Message> {
116    button(text(page.title_str()))
117        .style(if page != cur_page {
118            button::subtle
119        } else {
120            button::secondary
121        })
122        .on_press(Message::SelectPage(page))
123}
124
125pub fn link_button<'a, P>(placeholder: P, link: &'a str) -> tooltip::Tooltip<'a, Message>
126where
127    P: IntoFragment<'a>,
128{
129    tooltip(
130        button(text(placeholder))
131            .style(super::styles::link_button)
132            .padding(0)
133            .on_press(Message::Buttons(ButtonsMessage::LinkButtonPressed(
134                link.to_string(),
135            ))),
136        container(text(link).size(11).style(|s: &iced::Theme| text::Style {
137            color: Some(if s.extended_palette().is_dark {
138                s.palette().text
139            } else {
140                Color::WHITE
141            }),
142        }))
143        .padding(2)
144        .style(|_| container::Style {
145            background: Some(iced::Background::Color(Color::from_rgba8(0, 0, 0, 0.71))),
146            border: iced::Border {
147                radius: iced::border::Radius::from(2),
148                ..iced::Border::default()
149            },
150            ..Default::default()
151        }),
152        Position::Bottom,
153    )
154}