Merge branch 'master' into advanced-text
This commit is contained in:
commit
4bae457c37
73 changed files with 1586 additions and 703 deletions
|
|
@ -134,8 +134,8 @@ mod numeric_input {
|
|||
.map(u32::to_string)
|
||||
.as_deref()
|
||||
.unwrap_or(""),
|
||||
Event::InputChanged,
|
||||
)
|
||||
.on_input(Event::InputChanged)
|
||||
.padding(10),
|
||||
button("+", Event::IncrementPressed),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -18,10 +18,7 @@ pub struct Download<I> {
|
|||
url: String,
|
||||
}
|
||||
|
||||
async fn download<I: Copy>(
|
||||
id: I,
|
||||
state: State,
|
||||
) -> (Option<(I, Progress)>, State) {
|
||||
async fn download<I: Copy>(id: I, state: State) -> ((I, Progress), State) {
|
||||
match state {
|
||||
State::Ready(url) => {
|
||||
let response = reqwest::get(&url).await;
|
||||
|
|
@ -30,7 +27,7 @@ async fn download<I: Copy>(
|
|||
Ok(response) => {
|
||||
if let Some(total) = response.content_length() {
|
||||
(
|
||||
Some((id, Progress::Started)),
|
||||
(id, Progress::Started),
|
||||
State::Downloading {
|
||||
response,
|
||||
total,
|
||||
|
|
@ -38,10 +35,10 @@ async fn download<I: Copy>(
|
|||
},
|
||||
)
|
||||
} else {
|
||||
(Some((id, Progress::Errored)), State::Finished)
|
||||
((id, Progress::Errored), State::Finished)
|
||||
}
|
||||
}
|
||||
Err(_) => (Some((id, Progress::Errored)), State::Finished),
|
||||
Err(_) => ((id, Progress::Errored), State::Finished),
|
||||
}
|
||||
}
|
||||
State::Downloading {
|
||||
|
|
@ -55,7 +52,7 @@ async fn download<I: Copy>(
|
|||
let percentage = (downloaded as f32 / total as f32) * 100.0;
|
||||
|
||||
(
|
||||
Some((id, Progress::Advanced(percentage))),
|
||||
(id, Progress::Advanced(percentage)),
|
||||
State::Downloading {
|
||||
response,
|
||||
total,
|
||||
|
|
@ -63,8 +60,8 @@ async fn download<I: Copy>(
|
|||
},
|
||||
)
|
||||
}
|
||||
Ok(None) => (Some((id, Progress::Finished)), State::Finished),
|
||||
Err(_) => (Some((id, Progress::Errored)), State::Finished),
|
||||
Ok(None) => ((id, Progress::Finished), State::Finished),
|
||||
Err(_) => ((id, Progress::Errored), State::Finished),
|
||||
},
|
||||
State::Finished => {
|
||||
// We do not let the stream die, as it would start a
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ iced_winit = { path = "../../winit" }
|
|||
iced_wgpu = { path = "../../wgpu" }
|
||||
iced_widget = { path = "../../widget" }
|
||||
iced_renderer = { path = "../../renderer", features = ["wgpu", "tiny-skia"] }
|
||||
env_logger = "0.8"
|
||||
env_logger = "0.10"
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
console_error_panic_hook = "0.1.7"
|
||||
|
|
|
|||
|
|
@ -102,11 +102,10 @@ impl Program for Controls {
|
|||
.size(14)
|
||||
.style(Color::WHITE),
|
||||
)
|
||||
.push(text_input(
|
||||
"Placeholder",
|
||||
text,
|
||||
Message::TextChanged,
|
||||
)),
|
||||
.push(
|
||||
text_input("Placeholder", text)
|
||||
.on_input(Message::TextChanged),
|
||||
),
|
||||
),
|
||||
)
|
||||
.into()
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
#[cfg(target_arch = "wasm32")]
|
||||
let canvas_element = {
|
||||
console_log::init_with_level(log::Level::Debug)?;
|
||||
|
||||
std::panic::set_hook(Box::new(console_error_panic_hook::hook));
|
||||
|
||||
web_sys::window()
|
||||
|
|
@ -49,7 +50,7 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
.build(&event_loop)?;
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let window = winit::window::Window::new(&event_loop).unwrap();
|
||||
let window = winit::window::Window::new(&event_loop)?;
|
||||
|
||||
let physical_size = window.inner_size();
|
||||
let mut viewport = Viewport::with_physical_size(
|
||||
|
|
@ -61,7 +62,6 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
let mut clipboard = Clipboard::connect(&window);
|
||||
|
||||
// Initialize wgpu
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
let default_backend = wgpu::Backends::GL;
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
|
|
@ -95,12 +95,16 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
#[cfg(not(target_arch = "wasm32"))]
|
||||
let needed_limits = wgpu::Limits::default();
|
||||
|
||||
let capabilities = surface.get_capabilities(&adapter);
|
||||
|
||||
(
|
||||
surface
|
||||
.get_capabilities(&adapter)
|
||||
capabilities
|
||||
.formats
|
||||
.first()
|
||||
.iter()
|
||||
.filter(|format| format.describe().srgb)
|
||||
.copied()
|
||||
.next()
|
||||
.or_else(|| capabilities.formats.first().copied())
|
||||
.expect("Get preferred format"),
|
||||
adapter
|
||||
.request_device(
|
||||
|
|
|
|||
|
|
@ -213,12 +213,9 @@ impl Sandbox for App {
|
|||
column![
|
||||
scrollable(options).height(Length::Fill),
|
||||
row![
|
||||
text_input(
|
||||
"Add a new option",
|
||||
&self.input,
|
||||
Message::InputChanged,
|
||||
)
|
||||
.on_submit(Message::AddItem(self.input.clone())),
|
||||
text_input("Add a new option", &self.input)
|
||||
.on_input(Message::InputChanged)
|
||||
.on_submit(Message::AddItem(self.input.clone())),
|
||||
button(text(format!("Toggle Order ({})", self.order)))
|
||||
.on_press(Message::ToggleOrder)
|
||||
]
|
||||
|
|
|
|||
|
|
@ -133,18 +133,16 @@ impl Application for App {
|
|||
column![
|
||||
column![
|
||||
text("Email").size(12),
|
||||
text_input(
|
||||
"abc@123.com",
|
||||
&self.email,
|
||||
Message::Email
|
||||
)
|
||||
.on_submit(Message::Submit)
|
||||
.padding(5),
|
||||
text_input("abc@123.com", &self.email,)
|
||||
.on_input(Message::Email)
|
||||
.on_submit(Message::Submit)
|
||||
.padding(5),
|
||||
]
|
||||
.spacing(5),
|
||||
column![
|
||||
text("Password").size(12),
|
||||
text_input("", &self.password, Message::Password)
|
||||
text_input("", &self.password)
|
||||
.on_input(Message::Password)
|
||||
.on_submit(Message::Submit)
|
||||
.password()
|
||||
.padding(5),
|
||||
|
|
|
|||
|
|
@ -49,13 +49,11 @@ impl Sandbox for QRGenerator {
|
|||
.size(70)
|
||||
.style(Color::from([0.5, 0.5, 0.5]));
|
||||
|
||||
let input = text_input(
|
||||
"Type the data of your QR code here...",
|
||||
&self.data,
|
||||
Message::DataChanged,
|
||||
)
|
||||
.size(30)
|
||||
.padding(15);
|
||||
let input =
|
||||
text_input("Type the data of your QR code here...", &self.data)
|
||||
.on_input(Message::DataChanged)
|
||||
.size(30)
|
||||
.padding(15);
|
||||
|
||||
let mut content = column![title, input]
|
||||
.width(700)
|
||||
|
|
|
|||
|
|
@ -338,22 +338,36 @@ impl scrollable::StyleSheet for ScrollbarCustomStyle {
|
|||
style.active(&theme::Scrollable::Default)
|
||||
}
|
||||
|
||||
fn hovered(&self, style: &Self::Style) -> Scrollbar {
|
||||
style.hovered(&theme::Scrollable::Default)
|
||||
fn hovered(
|
||||
&self,
|
||||
style: &Self::Style,
|
||||
is_mouse_over_scrollbar: bool,
|
||||
) -> Scrollbar {
|
||||
style.hovered(&theme::Scrollable::Default, is_mouse_over_scrollbar)
|
||||
}
|
||||
|
||||
fn hovered_horizontal(&self, style: &Self::Style) -> Scrollbar {
|
||||
Scrollbar {
|
||||
background: style.active(&theme::Scrollable::default()).background,
|
||||
border_radius: 0.0,
|
||||
border_width: 0.0,
|
||||
border_color: Default::default(),
|
||||
scroller: Scroller {
|
||||
color: Color::from_rgb8(250, 85, 134),
|
||||
fn hovered_horizontal(
|
||||
&self,
|
||||
style: &Self::Style,
|
||||
is_mouse_over_scrollbar: bool,
|
||||
) -> Scrollbar {
|
||||
if is_mouse_over_scrollbar {
|
||||
Scrollbar {
|
||||
background: style
|
||||
.active(&theme::Scrollable::default())
|
||||
.background,
|
||||
border_radius: 0.0,
|
||||
border_width: 0.0,
|
||||
border_color: Default::default(),
|
||||
},
|
||||
scroller: Scroller {
|
||||
color: Color::from_rgb8(250, 85, 134),
|
||||
border_radius: 0.0,
|
||||
border_width: 0.0,
|
||||
border_color: Default::default(),
|
||||
},
|
||||
}
|
||||
} else {
|
||||
self.active(style)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,13 +90,10 @@ impl Sandbox for Styling {
|
|||
},
|
||||
);
|
||||
|
||||
let text_input = text_input(
|
||||
"Type something...",
|
||||
&self.input_value,
|
||||
Message::InputChanged,
|
||||
)
|
||||
.padding(10)
|
||||
.size(20);
|
||||
let text_input = text_input("Type something...", &self.input_value)
|
||||
.on_input(Message::InputChanged)
|
||||
.padding(10)
|
||||
.size(20);
|
||||
|
||||
let button = button("Submit")
|
||||
.padding(10)
|
||||
|
|
|
|||
|
|
@ -119,13 +119,15 @@ impl Application for App {
|
|||
column![
|
||||
subtitle(
|
||||
"Title",
|
||||
text_input("", &self.editing.title, Message::Title)
|
||||
text_input("", &self.editing.title)
|
||||
.on_input(Message::Title)
|
||||
.on_submit(Message::Add)
|
||||
.into()
|
||||
),
|
||||
subtitle(
|
||||
"Message",
|
||||
text_input("", &self.editing.body, Message::Body)
|
||||
text_input("", &self.editing.body)
|
||||
.on_input(Message::Body)
|
||||
.on_submit(Message::Add)
|
||||
.into()
|
||||
),
|
||||
|
|
|
|||
|
|
@ -210,15 +210,12 @@ impl Application for Todos {
|
|||
.style(Color::from([0.5, 0.5, 0.5]))
|
||||
.horizontal_alignment(alignment::Horizontal::Center);
|
||||
|
||||
let input = text_input(
|
||||
"What needs to be done?",
|
||||
input_value,
|
||||
Message::InputChanged,
|
||||
)
|
||||
.id(INPUT_ID.clone())
|
||||
.padding(15)
|
||||
.size(30)
|
||||
.on_submit(Message::CreateTask);
|
||||
let input = text_input("What needs to be done?", input_value)
|
||||
.id(INPUT_ID.clone())
|
||||
.on_input(Message::InputChanged)
|
||||
.on_submit(Message::CreateTask)
|
||||
.padding(15)
|
||||
.size(30);
|
||||
|
||||
let controls = view_controls(tasks, *filter);
|
||||
let filtered_tasks =
|
||||
|
|
@ -381,14 +378,12 @@ impl Task {
|
|||
.into()
|
||||
}
|
||||
TaskState::Editing => {
|
||||
let text_input = text_input(
|
||||
"Describe your task...",
|
||||
&self.description,
|
||||
TaskMessage::DescriptionEdited,
|
||||
)
|
||||
.id(Self::text_input_id(i))
|
||||
.on_submit(TaskMessage::FinishEdition)
|
||||
.padding(10);
|
||||
let text_input =
|
||||
text_input("Describe your task...", &self.description)
|
||||
.id(Self::text_input_id(i))
|
||||
.on_input(TaskMessage::DescriptionEdited)
|
||||
.on_submit(TaskMessage::FinishEdition)
|
||||
.padding(10);
|
||||
|
||||
row![
|
||||
text_input,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ use iced::widget::{
|
|||
scrollable, slider, text, text_input, toggler, vertical_space,
|
||||
};
|
||||
use iced::widget::{Button, Column, Container, Slider};
|
||||
use iced::{Color, Element, Length, Renderer, Sandbox, Settings};
|
||||
use iced::{Color, Element, Font, Length, Renderer, Sandbox, Settings};
|
||||
|
||||
pub fn main() -> iced::Result {
|
||||
env_logger::init();
|
||||
|
|
@ -127,6 +127,7 @@ impl Steps {
|
|||
Step::TextInput {
|
||||
value: String::new(),
|
||||
is_secure: false,
|
||||
is_showing_icon: false,
|
||||
},
|
||||
Step::Debugger,
|
||||
Step::End,
|
||||
|
|
@ -171,14 +172,32 @@ impl Steps {
|
|||
|
||||
enum Step {
|
||||
Welcome,
|
||||
Slider { value: u8 },
|
||||
RowsAndColumns { layout: Layout, spacing: u16 },
|
||||
Text { size: u16, color: Color },
|
||||
Radio { selection: Option<Language> },
|
||||
Toggler { can_continue: bool },
|
||||
Image { width: u16 },
|
||||
Slider {
|
||||
value: u8,
|
||||
},
|
||||
RowsAndColumns {
|
||||
layout: Layout,
|
||||
spacing: u16,
|
||||
},
|
||||
Text {
|
||||
size: u16,
|
||||
color: Color,
|
||||
},
|
||||
Radio {
|
||||
selection: Option<Language>,
|
||||
},
|
||||
Toggler {
|
||||
can_continue: bool,
|
||||
},
|
||||
Image {
|
||||
width: u16,
|
||||
},
|
||||
Scrollable,
|
||||
TextInput { value: String, is_secure: bool },
|
||||
TextInput {
|
||||
value: String,
|
||||
is_secure: bool,
|
||||
is_showing_icon: bool,
|
||||
},
|
||||
Debugger,
|
||||
End,
|
||||
}
|
||||
|
|
@ -194,6 +213,7 @@ pub enum StepMessage {
|
|||
ImageWidthChanged(u16),
|
||||
InputChanged(String),
|
||||
ToggleSecureInput(bool),
|
||||
ToggleTextInputIcon(bool),
|
||||
DebugToggled(bool),
|
||||
TogglerChanged(bool),
|
||||
}
|
||||
|
|
@ -256,6 +276,14 @@ impl<'a> Step {
|
|||
*can_continue = value;
|
||||
}
|
||||
}
|
||||
StepMessage::ToggleTextInputIcon(toggle) => {
|
||||
if let Step::TextInput {
|
||||
is_showing_icon, ..
|
||||
} = self
|
||||
{
|
||||
*is_showing_icon = toggle
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -303,9 +331,11 @@ impl<'a> Step {
|
|||
Self::rows_and_columns(*layout, *spacing)
|
||||
}
|
||||
Step::Scrollable => Self::scrollable(),
|
||||
Step::TextInput { value, is_secure } => {
|
||||
Self::text_input(value, *is_secure)
|
||||
}
|
||||
Step::TextInput {
|
||||
value,
|
||||
is_secure,
|
||||
is_showing_icon,
|
||||
} => Self::text_input(value, *is_secure, *is_showing_icon),
|
||||
Step::Debugger => Self::debugger(debug),
|
||||
Step::End => Self::end(),
|
||||
}
|
||||
|
|
@ -530,14 +560,25 @@ impl<'a> Step {
|
|||
)
|
||||
}
|
||||
|
||||
fn text_input(value: &str, is_secure: bool) -> Column<'a, StepMessage> {
|
||||
let text_input = text_input(
|
||||
"Type something to continue...",
|
||||
value,
|
||||
StepMessage::InputChanged,
|
||||
)
|
||||
.padding(10)
|
||||
.size(30);
|
||||
fn text_input(
|
||||
value: &str,
|
||||
is_secure: bool,
|
||||
is_showing_icon: bool,
|
||||
) -> Column<'a, StepMessage> {
|
||||
let mut text_input = text_input("Type something to continue...", value)
|
||||
.on_input(StepMessage::InputChanged)
|
||||
.padding(10)
|
||||
.size(30);
|
||||
|
||||
if is_showing_icon {
|
||||
text_input = text_input.icon(text_input::Icon {
|
||||
font: Font::default(),
|
||||
code_point: '🚀',
|
||||
size: Some(28.0),
|
||||
spacing: 10.0,
|
||||
side: text_input::Side::Right,
|
||||
});
|
||||
}
|
||||
|
||||
Self::container("Text input")
|
||||
.push("Use a text input to ask for different kinds of information.")
|
||||
|
|
@ -551,6 +592,11 @@ impl<'a> Step {
|
|||
is_secure,
|
||||
StepMessage::ToggleSecureInput,
|
||||
))
|
||||
.push(checkbox(
|
||||
"Show icon",
|
||||
is_showing_icon,
|
||||
StepMessage::ToggleTextInputIcon,
|
||||
))
|
||||
.push(
|
||||
"A text input produces a message every time it changes. It is \
|
||||
very easy to keep track of its contents:",
|
||||
|
|
|
|||
|
|
@ -13,63 +13,67 @@ use std::fmt;
|
|||
pub fn connect() -> Subscription<Event> {
|
||||
struct Connect;
|
||||
|
||||
subscription::unfold(
|
||||
subscription::channel(
|
||||
std::any::TypeId::of::<Connect>(),
|
||||
State::Disconnected,
|
||||
|state| async move {
|
||||
match state {
|
||||
State::Disconnected => {
|
||||
const ECHO_SERVER: &str = "ws://localhost:3030";
|
||||
100,
|
||||
|mut output| async move {
|
||||
let mut state = State::Disconnected;
|
||||
|
||||
match async_tungstenite::tokio::connect_async(ECHO_SERVER)
|
||||
loop {
|
||||
match &mut state {
|
||||
State::Disconnected => {
|
||||
const ECHO_SERVER: &str = "ws://127.0.0.1:3030";
|
||||
|
||||
match async_tungstenite::tokio::connect_async(
|
||||
ECHO_SERVER,
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok((websocket, _)) => {
|
||||
let (sender, receiver) = mpsc::channel(100);
|
||||
{
|
||||
Ok((websocket, _)) => {
|
||||
let (sender, receiver) = mpsc::channel(100);
|
||||
|
||||
(
|
||||
Some(Event::Connected(Connection(sender))),
|
||||
State::Connected(websocket, receiver),
|
||||
)
|
||||
}
|
||||
Err(_) => {
|
||||
tokio::time::sleep(
|
||||
tokio::time::Duration::from_secs(1),
|
||||
)
|
||||
.await;
|
||||
let _ = output
|
||||
.send(Event::Connected(Connection(sender)))
|
||||
.await;
|
||||
|
||||
(Some(Event::Disconnected), State::Disconnected)
|
||||
}
|
||||
}
|
||||
}
|
||||
State::Connected(mut websocket, mut input) => {
|
||||
let mut fused_websocket = websocket.by_ref().fuse();
|
||||
state = State::Connected(websocket, receiver);
|
||||
}
|
||||
Err(_) => {
|
||||
tokio::time::sleep(
|
||||
tokio::time::Duration::from_secs(1),
|
||||
)
|
||||
.await;
|
||||
|
||||
futures::select! {
|
||||
received = fused_websocket.select_next_some() => {
|
||||
match received {
|
||||
Ok(tungstenite::Message::Text(message)) => {
|
||||
(
|
||||
Some(Event::MessageReceived(Message::User(message))),
|
||||
State::Connected(websocket, input)
|
||||
)
|
||||
}
|
||||
Ok(_) => {
|
||||
(None, State::Connected(websocket, input))
|
||||
}
|
||||
Err(_) => {
|
||||
(Some(Event::Disconnected), State::Disconnected)
|
||||
}
|
||||
let _ = output.send(Event::Disconnected).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
State::Connected(websocket, input) => {
|
||||
let mut fused_websocket = websocket.by_ref().fuse();
|
||||
|
||||
message = input.select_next_some() => {
|
||||
let result = websocket.send(tungstenite::Message::Text(message.to_string())).await;
|
||||
futures::select! {
|
||||
received = fused_websocket.select_next_some() => {
|
||||
match received {
|
||||
Ok(tungstenite::Message::Text(message)) => {
|
||||
let _ = output.send(Event::MessageReceived(Message::User(message))).await;
|
||||
}
|
||||
Err(_) => {
|
||||
let _ = output.send(Event::Disconnected).await;
|
||||
|
||||
if result.is_ok() {
|
||||
(None, State::Connected(websocket, input))
|
||||
} else {
|
||||
(Some(Event::Disconnected), State::Disconnected)
|
||||
state = State::Disconnected;
|
||||
}
|
||||
Ok(_) => continue,
|
||||
}
|
||||
}
|
||||
|
||||
message = input.select_next_some() => {
|
||||
let result = websocket.send(tungstenite::Message::Text(message.to_string())).await;
|
||||
|
||||
if result.is_err() {
|
||||
let _ = output.send(Event::Disconnected).await;
|
||||
|
||||
state = State::Disconnected;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -125,12 +125,9 @@ impl Application for WebSocket {
|
|||
};
|
||||
|
||||
let new_message_input = {
|
||||
let mut input = text_input(
|
||||
"Type a message...",
|
||||
&self.new_message,
|
||||
Message::NewMessageChanged,
|
||||
)
|
||||
.padding(10);
|
||||
let mut input = text_input("Type a message...", &self.new_message)
|
||||
.on_input(Message::NewMessageChanged)
|
||||
.padding(10);
|
||||
|
||||
let mut button = button(
|
||||
text("Send")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue