#![windows_subsystem = "windows"]
#[allow(deprecated)]
use druid::widget::Parse;
use druid::widget::{
Checkbox, CrossAxisAlignment, Flex, Label, LensWrap, MainAxisAlignment, Painter, Scroll,
Stepper, TextBox,
};
use druid::{
theme, AppLauncher, Color, Data, FontDescriptor, FontFamily, Key, Lens, LensExt,
LocalizedString, PlatformError, RenderContext, Widget, WidgetExt, WindowDesc,
};
use std::fmt::Display;
const MY_CUSTOM_FONT: Key<FontDescriptor> = Key::new("org.linebender.example.my-custom-font");
const COLUMN_WIDTH: f64 = 360.0;
#[derive(Clone, Lens, Data)]
struct AppData {
text: String,
size: f64,
mono: bool,
}
impl Display for AppData {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Size {:.1}{}: {}",
self.size,
if self.mono { " mono" } else { "" },
self.text
)
}
}
pub fn main() -> Result<(), PlatformError> {
let main_window = WindowDesc::new(ui_builder()).title(
LocalizedString::new("styled-text-demo-window-title").with_placeholder("Type Styler"),
);
let data = AppData {
text: "Here's some sample text".to_string(),
size: 24.0,
mono: false,
};
AppLauncher::with_window(main_window)
.log_to_console()
.launch(data)?;
Ok(())
}
fn ui_builder() -> impl Widget<AppData> {
let my_painter = Painter::new(|ctx, _, _| {
let bounds = ctx.size().to_rect();
if ctx.is_hot() {
ctx.fill(bounds, &Color::rgba8(0, 0, 0, 128));
}
if ctx.is_active() {
ctx.stroke(bounds, &Color::WHITE, 2.0);
}
});
let label =
Label::new(|data: &String, _env: &_| format!("Default: {data}")).lens(AppData::text);
let styled_label = Label::new(|data: &AppData, _env: &_| format!("{data}"))
.with_text_color(theme::PRIMARY_LIGHT)
.with_font(MY_CUSTOM_FONT)
.background(my_painter)
.on_click(|_, data, _| {
data.size *= 1.1;
})
.env_scope(|env: &mut druid::Env, data: &AppData| {
let new_font = if data.mono {
FontDescriptor::new(FontFamily::MONOSPACE)
} else {
FontDescriptor::new(FontFamily::SYSTEM_UI)
}
.with_size(data.size);
env.set(MY_CUSTOM_FONT, new_font);
});
let labels = Scroll::new(
Flex::column()
.cross_axis_alignment(CrossAxisAlignment::Start)
.with_child(label)
.with_default_spacer()
.with_child(styled_label),
)
.expand_height()
.fix_width(COLUMN_WIDTH);
let stepper = Stepper::new()
.with_range(0.0, 100.0)
.with_step(1.0)
.with_wraparound(false)
.lens(AppData::size);
#[allow(deprecated)]
let stepper_textbox = LensWrap::new(
Parse::new(TextBox::new()),
AppData::size.map(|x| Some(*x), |x, y| *x = y.unwrap_or(24.0)),
);
let mono_checkbox = Checkbox::new("Monospace").lens(AppData::mono);
let stepper_row = Flex::row()
.with_child(stepper_textbox)
.with_child(stepper)
.with_default_spacer()
.with_child(mono_checkbox);
let input = TextBox::multiline()
.with_placeholder("Your sample text here :)")
.fix_width(COLUMN_WIDTH)
.fix_height(140.0)
.lens(AppData::text);
Flex::column()
.main_axis_alignment(MainAxisAlignment::Center)
.with_default_spacer()
.with_flex_child(labels, 1.0)
.with_default_spacer()
.with_child(input)
.with_default_spacer()
.with_child(stepper_row)
.with_default_spacer()
}