#![allow(missing_docs)] use iced_debug as debug; use iced_program as program; use iced_widget as widget; use iced_widget::core; use iced_widget::runtime; use iced_widget::runtime::futures; mod comet; mod executor; mod time_machine; use crate::core::keyboard; use crate::core::theme::{self, Base, Theme}; use crate::core::time::seconds; use crate::core::window; use crate::core::{Color, Element, Length::Fill}; use crate::futures::Subscription; use crate::program::Program; use crate::runtime::Task; use crate::time_machine::TimeMachine; use crate::widget::{ bottom_right, button, center, column, container, horizontal_space, opaque, row, scrollable, stack, text, themer, }; use std::fmt; use std::thread; pub fn attach(program: impl Program + 'static) -> impl Program { struct Attach
{ program: P, } impl
Program for Attach
where P: Program + 'static, { type State = DevTools
; type Message = Event
;
type Theme = P::Theme;
type Renderer = P::Renderer;
type Executor = P::Executor;
fn name() -> &'static str {
P::name()
}
fn boot(&self) -> (Self::State, Task
where
P: Program,
{
state: P::State,
mode: Mode,
show_notification: bool,
time_machine: TimeMachine ,
}
#[derive(Debug, Clone)]
enum Message {
HideNotification,
ToggleComet,
CometLaunched(Result<(), comet::Error>),
InstallComet,
InstallationProgressed(Result DevTools
where
P: Program + 'static,
{
fn new(state: P::State) -> (Self, Task ) -> Task , P::Theme, P::Renderer> {
let state = self.state();
let view = {
let view = program.view(state, window);
if self.time_machine.is_rewinding() {
view.map(|_| Event::Discard)
} else {
view.map(Event::Program)
}
};
let theme = program.theme(state, window);
let derive_theme = move || {
theme
.palette()
.map(|palette| Theme::custom("DevTools".to_owned(), palette))
.unwrap_or_default()
};
let mode = match &self.mode {
Mode::None => None,
Mode::Setup(setup) => {
let stage: Element<'_, _, Theme, P::Renderer> = match setup {
Setup::Idle { goal } => {
let controls = row![
button(text("Cancel").center().width(Fill))
.width(100)
.on_press(Message::CancelSetup)
.style(button::danger),
horizontal_space(),
button(
text(match goal {
Goal::Installation => "Install",
Goal::Update { .. } => "Update",
})
.center()
.width(Fill)
)
.width(100)
.on_press(Message::InstallComet)
.style(button::success),
];
let command = container(
text(
"cargo install --locked \
--git https://github.com/iced-rs/comet.git",
)
.size(14),
)
.width(Fill)
.padding(5)
.style(container::dark);
match goal {
Goal::Installation => column![
text("comet is not installed!").size(20),
"In order to display performance \
metrics, the comet debugger must \
be installed in your system.",
"The comet debugger is an official \
companion tool that helps you debug \
your iced applications.",
"Do you wish to install it with the \
following command?",
command,
controls,
]
.spacing(20),
Goal::Update { revision } => column![
text("comet is out of date!").size(20),
text!(
"The installed revision is \"{current}\", \
but the latest compatible is \"{compatible}\".",
current = revision
.as_deref()
.unwrap_or("Unknown"),
compatible = comet::COMPATIBLE_REVISION,
),
"Do you wish to update it with the following \
command?",
command,
controls,
]
.spacing(20),
}
.into()
}
Setup::Running { logs } => column![
text("Installing comet...").size(20),
container(
scrollable(
column(
logs.iter()
.map(|log| text(log).size(12).into()),
)
.spacing(3),
)
.spacing(10)
.width(Fill)
.height(300)
.anchor_bottom(),
)
.padding(10)
.style(container::dark)
]
.spacing(20)
.into(),
};
let setup = center(
container(stage)
.padding(20)
.width(500)
.style(container::bordered_box),
)
.padding(10)
.style(|_theme| {
container::Style::default()
.background(Color::BLACK.scale_alpha(0.8))
});
Some(setup)
}
}
.map(|mode| {
themer(derive_theme(), Element::from(mode).map(Event::Message))
});
let notification = self.show_notification.then(|| {
themer(
derive_theme(),
bottom_right(opaque(
container(text("Press F12 to open debug metrics"))
.padding(10)
.style(container::dark),
)),
)
});
stack![view]
.height(Fill)
.push_maybe(mode.map(opaque))
.push_maybe(notification)
.into()
}
fn subscription(&self, program: &P) -> Subscription
where
P: Program,
{
Message(Message),
Program(P::Message),
Command(debug::Command),
Discard,
}
impl fmt::Debug for Event
where
P: Program,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Message(message) => message.fmt(f),
Self::Program(message) => message.fmt(f),
Self::Command(command) => command.fmt(f),
Self::Discard => f.write_str("Discard"),
}
}
}
#[cfg(feature = "time-travel")]
impl Clone for Event
where
P: Program,
{
fn clone(&self) -> Self {
match self {
Self::Message(message) => Self::Message(message.clone()),
Self::Program(message) => Self::Program(message.clone()),
Self::Command(command) => Self::Command(*command),
Self::Discard => Self::Discard,
}
}
}