257 lines
7.9 KiB
Rust
257 lines
7.9 KiB
Rust
use crate::data;
|
|
use druid::widget::{Controller, Padding};
|
|
use druid::{
|
|
widget::{Container, Flex, Label, LensWrap, TextBox},
|
|
Color, FontDescriptor, FontFamily, FontWeight, RenderContext, Widget, WidgetExt, WidgetPod,
|
|
};
|
|
use druid::{Data, LifeCycle, TextAlignment};
|
|
|
|
pub struct ModalContainer {
|
|
child: WidgetPod<data::AppData, Box<dyn Widget<data::AppData>>>,
|
|
modal: Option<WidgetPod<data::AppData, Box<dyn Widget<data::AppData>>>>,
|
|
}
|
|
|
|
impl ModalContainer {
|
|
pub fn new(child: impl Widget<data::AppData> + 'static) -> Self {
|
|
Self {
|
|
child: WidgetPod::new(child).boxed(),
|
|
modal: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Widget<data::AppData> for ModalContainer {
|
|
fn event(
|
|
&mut self,
|
|
ctx: &mut druid::EventCtx,
|
|
event: &druid::Event,
|
|
data: &mut data::AppData,
|
|
env: &druid::Env,
|
|
) {
|
|
if let druid::Event::Notification(n) = event {
|
|
if n.is(crate::commands::CLOSE_MODAL) {
|
|
self.modal = None;
|
|
data.modals.rename_block = data::RenameBlock::default();
|
|
ctx.children_changed();
|
|
return;
|
|
}
|
|
}
|
|
|
|
if let druid::Event::Command(c) = event {
|
|
if let Some(idx) = c.get(crate::commands::RENAME_BLOCK) {
|
|
data.modals.rename_block = data::RenameBlock {
|
|
name: data
|
|
.blocks
|
|
.get(*idx)
|
|
.map(|i| i.name.clone())
|
|
.unwrap_or_default(),
|
|
input: data
|
|
.blocks
|
|
.get(*idx)
|
|
.map(|i| i.name.clone())
|
|
.unwrap_or_default(),
|
|
block_index: *idx,
|
|
};
|
|
self.modal = Some(WidgetPod::new(rename_block()).boxed());
|
|
ctx.children_changed();
|
|
return;
|
|
}
|
|
}
|
|
|
|
if let Some(m) = self.modal.as_mut() {
|
|
m.event(ctx, event, data, env);
|
|
} else {
|
|
self.child.event(ctx, event, data, env);
|
|
}
|
|
}
|
|
|
|
fn lifecycle(
|
|
&mut self,
|
|
ctx: &mut druid::LifeCycleCtx,
|
|
event: &druid::LifeCycle,
|
|
data: &data::AppData,
|
|
env: &druid::Env,
|
|
) {
|
|
if let Some(modal) = self.modal.as_mut() {
|
|
modal.lifecycle(ctx, event, data, env);
|
|
}
|
|
self.child.lifecycle(ctx, event, data, env);
|
|
}
|
|
|
|
fn update(
|
|
&mut self,
|
|
ctx: &mut druid::UpdateCtx,
|
|
_old_data: &data::AppData,
|
|
data: &data::AppData,
|
|
env: &druid::Env,
|
|
) {
|
|
if let Some(modal) = self.modal.as_mut() {
|
|
modal.update(ctx, data, env);
|
|
}
|
|
self.child.update(ctx, data, env);
|
|
}
|
|
|
|
fn layout(
|
|
&mut self,
|
|
ctx: &mut druid::LayoutCtx,
|
|
bc: &druid::BoxConstraints,
|
|
data: &data::AppData,
|
|
env: &druid::Env,
|
|
) -> druid::Size {
|
|
if let Some(modal) = self.modal.as_mut() {
|
|
modal.layout(ctx, bc, data, env);
|
|
}
|
|
self.child.layout(ctx, bc, data, env)
|
|
}
|
|
|
|
fn paint(&mut self, ctx: &mut druid::PaintCtx, data: &data::AppData, env: &druid::Env) {
|
|
self.child.paint(ctx, data, env);
|
|
let full_rect = ctx.size().to_rect();
|
|
if let Some(m) = self.modal.as_mut() {
|
|
ctx.fill(full_rect, &druid::Color::rgba8(0, 0, 0, 100));
|
|
m.paint(ctx, data, env)
|
|
}
|
|
}
|
|
}
|
|
|
|
fn rename_block() -> impl Widget<data::AppData> {
|
|
modal_container(
|
|
"Rename Block",
|
|
(300.0, 150.0),
|
|
Flex::column()
|
|
.with_child(
|
|
Label::new("Block name")
|
|
.with_text_color(druid::Color::WHITE)
|
|
.with_text_alignment(TextAlignment::Start)
|
|
.with_font(
|
|
FontDescriptor::new(FontFamily::SYSTEM_UI)
|
|
.with_weight(FontWeight::BOLD)
|
|
.with_size(14.0),
|
|
)
|
|
.fix_width(300.0),
|
|
)
|
|
.with_spacer(5.0)
|
|
.with_child(LensWrap::new(
|
|
LensWrap::new(
|
|
TextBox::default()
|
|
.lens(data::RenameBlock::input)
|
|
.fix_width(300.0),
|
|
data::Modals::rename_block,
|
|
),
|
|
data::AppData::modals,
|
|
))
|
|
.with_spacer(20.0)
|
|
.with_child(
|
|
Flex::row()
|
|
.must_fill_main_axis(true)
|
|
.with_child(modal_action("Cancel").on_click(|ctx, _, _| {
|
|
ctx.submit_notification(crate::commands::CLOSE_MODAL)
|
|
}))
|
|
.with_flex_spacer(1.0)
|
|
.with_child(modal_action("Rename").on_click(
|
|
|ctx, data: &mut data::AppData, _| {
|
|
let input = data.modals.rename_block.input.clone();
|
|
if let Some(blk) =
|
|
data.blocks.get_mut(data.modals.rename_block.block_index)
|
|
{
|
|
blk.name = input;
|
|
data.modals.rename_block = data::RenameBlock::default();
|
|
ctx.submit_notification(crate::commands::CLOSE_MODAL)
|
|
}
|
|
},
|
|
))
|
|
.fix_width(300.0),
|
|
),
|
|
)
|
|
}
|
|
|
|
fn modal_container<S: Into<druid::Size>>(
|
|
title: &str,
|
|
size: S,
|
|
child: impl Widget<data::AppData> + 'static,
|
|
) -> impl Widget<data::AppData> {
|
|
let size = size.into();
|
|
Flex::column()
|
|
.with_child(modal_title(title, size.width))
|
|
.with_child(Padding::new(15.0, child))
|
|
.background(Color::rgb8(20, 20, 20))
|
|
.center()
|
|
.fix_size(size.width, size.height)
|
|
}
|
|
|
|
fn modal_title(title: &str, width: f64) -> impl Widget<data::AppData> {
|
|
Container::new(Padding::new(
|
|
8.0,
|
|
Flex::row()
|
|
.with_spacer(10.0)
|
|
.with_child(
|
|
Label::new(title)
|
|
.with_text_color(Color::rgb8(150, 150, 150))
|
|
.with_text_alignment(TextAlignment::Start)
|
|
.with_font(
|
|
FontDescriptor::new(FontFamily::SYSTEM_UI)
|
|
.with_weight(FontWeight::BOLD)
|
|
.with_size(14.0),
|
|
)
|
|
.fix_width(width),
|
|
)
|
|
.with_spacer(10.0),
|
|
))
|
|
.background(Color::rgb8(10, 10, 10))
|
|
}
|
|
|
|
fn modal_action<T: Data>(text: &str) -> impl Widget<T> {
|
|
Container::new(Padding::new(5.0, Label::new(text)))
|
|
.rounded(4.0)
|
|
.controller(ModalActionController)
|
|
}
|
|
|
|
pub struct ModalActionController;
|
|
|
|
impl<T: Data> Controller<T, Container<T>> for ModalActionController {
|
|
fn event(
|
|
&mut self,
|
|
child: &mut Container<T>,
|
|
ctx: &mut druid::EventCtx,
|
|
event: &druid::Event,
|
|
data: &mut T,
|
|
env: &druid::Env,
|
|
) {
|
|
ctx.set_cursor(&druid::Cursor::Pointer);
|
|
child.event(ctx, event, data, env)
|
|
}
|
|
|
|
fn lifecycle(
|
|
&mut self,
|
|
child: &mut Container<T>,
|
|
ctx: &mut druid::LifeCycleCtx,
|
|
event: &druid::LifeCycle,
|
|
data: &T,
|
|
env: &druid::Env,
|
|
) {
|
|
match event {
|
|
LifeCycle::HotChanged(true) => {
|
|
child.set_background(Color::rgb8(100, 100, 100));
|
|
ctx.request_paint();
|
|
}
|
|
LifeCycle::HotChanged(false) => {
|
|
child.set_background(Color::TRANSPARENT);
|
|
ctx.request_paint();
|
|
}
|
|
_ => {}
|
|
}
|
|
child.lifecycle(ctx, event, data, env)
|
|
}
|
|
|
|
fn update(
|
|
&mut self,
|
|
child: &mut Container<T>,
|
|
ctx: &mut druid::UpdateCtx,
|
|
old_data: &T,
|
|
data: &T,
|
|
env: &druid::Env,
|
|
) {
|
|
child.update(ctx, old_data, data, env)
|
|
}
|
|
}
|