diff --git a/.vscode/launch.json b/.vscode/launch.json index c66a6827..5b94a8d7 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -292,6 +292,24 @@ "args": [], "cwd": "${workspaceFolder}" }, + { + "type": "lldb", + "request": "launch", + "name": "Debug executable 'widget_id'", + "cargo": { + "args": [ + "build", + "--bin=widget_id", + "--package=widget_id" + ], + "filter": { + "name": "widget_id", + "kind": "bin" + } + }, + "args": [], + "cwd": "${workspaceFolder}" + }, { "type": "lldb", "request": "launch", diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..4d9636b5 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "rust-analyzer.showUnlinkedFileNotification": false +} \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index e70c6c27..d4d3a021 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -98,7 +98,8 @@ members = [ "examples/split_scroller", "examples/menu", "examples/spinner", - "examples/context_menu" + "examples/context_menu", + "examples/WidgetIDReturn" ] [workspace.dependencies.iced] diff --git a/examples/WidgetIDReturn/Cargo.toml b/examples/WidgetIDReturn/Cargo.toml new file mode 100644 index 00000000..9236c960 --- /dev/null +++ b/examples/WidgetIDReturn/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "widget_id" +version = "0.1.0" +authors = ["Andrew Wheeler "] +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +iced_aw = { workspace = true, features = [ + "number_input", + "icons", +] } +iced.workspace = true +num-traits = "0.2.16" \ No newline at end of file diff --git a/examples/WidgetIDReturn/src/main.rs b/examples/WidgetIDReturn/src/main.rs new file mode 100644 index 00000000..1d224582 --- /dev/null +++ b/examples/WidgetIDReturn/src/main.rs @@ -0,0 +1,121 @@ +use iced::{ + alignment, font, + theme::Theme, + widget::{container, text, Column, Container, Row, Text}, + window, Alignment, Application, Command, Element, Length, Settings, +}; + +#[derive(Debug)] +enum NumberInputDemo { + Loading, + Loaded(State), +} + +#[derive(Debug)] +pub struct State { + value: [NumInput; 2], +} + +#[derive(Debug, Clone)] +pub enum Message { + Loaded(Result<(), String>), + GenericF32Input((usize, NumInputMessage)), + FontLoaded(Result<(), font::Error>), +} + +fn main() -> iced::Result { + NumberInputDemo::run(Settings { + default_text_size: 12.0, + window: window::Settings { + size: (500, 400), + ..Default::default() + }, + ..Settings::default() + }) +} + +mod numberinput; + +use numberinput::*; + +async fn load() -> Result<(), String> { + Ok(()) +} + +impl Application for NumberInputDemo { + type Message = Message; + type Theme = Theme; + type Executor = iced::executor::Default; + type Flags = (); + + fn new(_flags: ()) -> (NumberInputDemo, Command) { + ( + NumberInputDemo::Loading, + Command::batch(vec![ + font::load(iced_aw::graphics::icons::ICON_FONT_BYTES).map(Message::FontLoaded), + Command::perform(load(), Message::Loaded), + ]), + ) + } + + fn title(&self) -> String { + String::from("Number Input Demo") + } + + fn update(&mut self, message: self::Message) -> Command { + match self { + NumberInputDemo::Loading => { + if let Message::Loaded(_) = message { + *self = NumberInputDemo::Loaded(State { + value: [NumInput::new(27.0), NumInput::new(5.0)], + }) + } + } + NumberInputDemo::Loaded(State { value }) => { + if let Message::GenericF32Input((id, val)) = message { + value[id].value = val.get_data(); + } + } + } + + Command::none() + } + + fn view(&self) -> Element { + match self { + NumberInputDemo::Loading => container( + text("Loading...") + .horizontal_alignment(alignment::Horizontal::Center) + .size(50), + ) + .width(Length::Fill) + .height(Length::Fill) + .center_y() + .center_x() + .into(), + NumberInputDemo::Loaded(State { value }) => { + let mut column1 = Column::new(); + + for (id, val) in value.iter().enumerate() { + let lb_minute = Text::new(format!("Number Input {}:", id)); + let txt_minute = val.view(id, 1.0, 255.0, 0.5, Message::GenericF32Input, None); + + column1 = column1.push( + Row::new() + .spacing(10) + .align_items(Alignment::Center) + .push(lb_minute) + .push(txt_minute), + ); + } + + Container::new(column1) + .width(Length::Fill) + .height(Length::Fill) + .center_x() + .center_y() + .into() + } + } + } +} diff --git a/examples/WidgetIDReturn/src/numberinput.rs b/examples/WidgetIDReturn/src/numberinput.rs new file mode 100644 index 00000000..b257b842 --- /dev/null +++ b/examples/WidgetIDReturn/src/numberinput.rs @@ -0,0 +1,79 @@ +use iced::{Element, Length}; +use iced_aw::{NumberInput, NumberInputStyles}; +use num_traits::{Num, NumAssignOps}; +use std::fmt::Display; +use std::marker::PhantomData; +use std::str::FromStr; + +#[derive(Debug, Default)] +pub struct NumInput { + phantomdata: PhantomData, + pub value: V, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum NumInputMessage { + Change(V), +} + +impl NumInputMessage +where + V: Num + NumAssignOps + PartialOrd + Display + FromStr + Copy, +{ + pub fn get_data(&self) -> V { + let NumInputMessage::Change(data) = self; + *data + } +} + +impl NumInputMessage +where + V: Eq + Copy, +{ + pub fn get_enum(&self) -> V { + let NumInputMessage::Change(data) = self; + *data + } +} + +impl NumInput +where + V: Num + NumAssignOps + PartialOrd + Display + FromStr + Copy, + M: Clone, +{ + pub fn new(value: V) -> NumInput + where + V: 'static, + { + NumInput { + phantomdata: PhantomData, + value, + } + } + + pub fn view( + &self, + id: usize, + min: V, + max: V, + step: V, + on_change: F, + style: Option, + ) -> Element + where + F: 'static + Fn((usize, NumInputMessage)) -> M + Copy, + V: 'static, + M: 'static, + { + let mut input = NumberInput::new(self.value, max, NumInputMessage::Change) + .step(step) + .min(min) + .width(Length::Shrink); + + if let Some(style) = style { + input = input.style(style); + } + + Element::new(input).map(move |i| on_change((id, i))) + } +} diff --git a/examples/number_input/src/main.rs b/examples/number_input/src/main.rs index 1cbc86b4..7132949a 100644 --- a/examples/number_input/src/main.rs +++ b/examples/number_input/src/main.rs @@ -26,7 +26,7 @@ pub enum Message { fn main() -> iced::Result { NumberInputDemo::run(Settings { - default_text_size: 65.0, + default_text_size: 12.0, window: window::Settings { size: (250, 200), ..Default::default() diff --git a/src/native/tab_bar.rs b/src/native/tab_bar.rs index 7c5c4bbf..74d5fddc 100644 --- a/src/native/tab_bar.rs +++ b/src/native/tab_bar.rs @@ -332,45 +332,50 @@ where self.tab_labels .iter() .fold(Row::::new(), |row, tab_label| { - let label = match tab_label { - TabLabel::Icon(icon) => Column::new().align_items(Alignment::Center).push( - Text::new(icon.to_string()) - .size(self.icon_size) - .font(self.icon_font.unwrap_or_default()) - .horizontal_alignment(alignment::Horizontal::Center) - .vertical_alignment(alignment::Vertical::Center), - ), - TabLabel::Text(text) => Column::new().align_items(Alignment::Center).push( - Text::new(text) - .size(self.text_size) - .font(self.text_font.unwrap_or_default()) - .horizontal_alignment(alignment::Horizontal::Center) - .vertical_alignment(alignment::Vertical::Center), - ), - TabLabel::IconText(icon, text) => Column::new() - .align_items(Alignment::Center) - .push( - Text::new(icon.to_string()) - .size(self.icon_size) - .font(self.icon_font.unwrap_or_default()) - .horizontal_alignment(alignment::Horizontal::Center) - .vertical_alignment(alignment::Vertical::Center), - ) - .push( - Text::new(text) - .size(self.text_size) - .width(self.tab_width) - .font(self.text_font.unwrap_or_default()), - ), - } - .width(self.tab_width) - .height(self.height); - let mut label_row = Row::new() + .push( + match tab_label { + TabLabel::Icon(icon) => { + Column::new().align_items(Alignment::Center).push( + Text::new(icon.to_string()) + .size(self.icon_size) + .font(self.icon_font.unwrap_or_default()) + .horizontal_alignment(alignment::Horizontal::Center) + .vertical_alignment(alignment::Vertical::Center), + ) + } + TabLabel::Text(text) => { + Column::new().align_items(Alignment::Center).push( + Text::new(text) + .size(self.text_size) + .font(self.text_font.unwrap_or_default()) + .horizontal_alignment(alignment::Horizontal::Center) + .vertical_alignment(alignment::Vertical::Center), + ) + } + TabLabel::IconText(icon, text) => Column::new() + .align_items(Alignment::Center) + .push( + Text::new(icon.to_string()) + .size(self.icon_size) + .font(self.icon_font.unwrap_or_default()) + .horizontal_alignment(alignment::Horizontal::Center) + .vertical_alignment(alignment::Vertical::Center), + ) + .push( + Text::new(text) + .size(self.text_size) + .font(self.text_font.unwrap_or_default()) + .horizontal_alignment(alignment::Horizontal::Center) + .vertical_alignment(alignment::Vertical::Center), + ), + } + .width(self.tab_width) + .height(self.height), + ) .align_items(Alignment::Center) .padding(self.padding) - .width(self.tab_width) - .push(label); + .width(self.tab_width); if self.on_close.is_some() { label_row = label_row.push( @@ -386,7 +391,7 @@ where .width(self.width) .height(self.height) .spacing(self.spacing) - .layout(renderer, limits) + .layout(renderer, &limits.loose()) } fn on_event( @@ -581,7 +586,7 @@ fn draw_tab( size: icon_data.1, color: style.icon_color, font: icon_data.0, - horizontal_alignment: Horizontal::Center, + horizontal_alignment: Horizontal::Left, vertical_alignment: Vertical::Center, line_height: LineHeight::Relative(1.3), shaping: iced_widget::text::Shaping::Advanced,