use iced::alignment::{self, Alignment}; use iced::mouse; use iced::widget::{ canvas, checkbox, column, horizontal_space, row, slider, text, }; use iced::{ Element, Length, Point, Rectangle, Renderer, Sandbox, Settings, Theme, Vector, }; pub fn main() -> iced::Result { VectorialText::run(Settings { antialiasing: true, ..Settings::default() }) } struct VectorialText { state: State, } #[derive(Debug, Clone, Copy)] enum Message { SizeChanged(f32), AngleChanged(f32), ScaleChanged(f32), ToggleJapanese(bool), } impl Sandbox for VectorialText { type Message = Message; fn new() -> Self { Self { state: State::new(), } } fn title(&self) -> String { String::from("Vectorial Text - Iced") } fn update(&mut self, message: Message) { match message { Message::SizeChanged(size) => { self.state.size = size; } Message::AngleChanged(angle) => { self.state.angle = angle; } Message::ScaleChanged(scale) => { self.state.scale = scale; } Message::ToggleJapanese(use_japanese) => { self.state.use_japanese = use_japanese; } } self.state.cache.clear(); } fn view(&self) -> Element { let slider_with_label = |label, range, value, message: fn(f32) -> _| { column![ row![ text(label), horizontal_space(Length::Fill), text(format!("{:.2}", value)) ], slider(range, value, message).step(0.01) ] .spacing(2) }; column![ canvas(&self.state).width(Length::Fill).height(Length::Fill), column![ checkbox("Use Japanese", self.state.use_japanese,) .on_toggle(Message::ToggleJapanese), row![ slider_with_label( "Size", 2.0..=80.0, self.state.size, Message::SizeChanged, ), slider_with_label( "Angle", 0.0..=360.0, self.state.angle, Message::AngleChanged, ), slider_with_label( "Scale", 1.0..=20.0, self.state.scale, Message::ScaleChanged, ), ] .spacing(20), ] .align_items(Alignment::Center) .spacing(10) ] .spacing(10) .padding(20) .into() } fn theme(&self) -> Theme { Theme::Dark } } struct State { size: f32, angle: f32, scale: f32, use_japanese: bool, cache: canvas::Cache, } impl State { pub fn new() -> Self { Self { size: 40.0, angle: 0.0, scale: 1.0, use_japanese: false, cache: canvas::Cache::new(), } } } impl canvas::Program for State { type State = (); fn draw( &self, _state: &Self::State, renderer: &Renderer, theme: &Theme, bounds: Rectangle, _cursor: mouse::Cursor, ) -> Vec { let geometry = self.cache.draw(renderer, bounds.size(), |frame| { let palette = theme.palette(); let center = bounds.center(); frame.translate(Vector::new(center.x, center.y)); frame.scale(self.scale); frame.rotate(self.angle * std::f32::consts::PI / 180.0); frame.fill_text(canvas::Text { position: Point::new(0.0, 0.0), color: palette.text, size: self.size.into(), content: String::from(if self.use_japanese { "ベクトルテキスト🎉" } else { "Vectorial Text! 🎉" }), horizontal_alignment: alignment::Horizontal::Center, vertical_alignment: alignment::Vertical::Center, shaping: text::Shaping::Advanced, ..canvas::Text::default() }); }); vec![geometry] } }