diff --git a/Cargo.lock b/Cargo.lock index fca3e6a..95217aa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1569,7 +1569,6 @@ dependencies = [ name = "icy_browser" version = "0.1.0" dependencies = [ - "cmake", "env_home", "iced", "iced_aw", diff --git a/Cargo.toml b/Cargo.toml index 2c1c1d0..141ce1c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,12 @@ codegen-units = 1 lto = "fat" strip = "debuginfo" panic = "abort" +incremental = true + +[profile.dev] +incremental = true +opt-level = "s" +lto = "thin" [build] rustflags = ["-Z", "threads=8"] @@ -39,5 +45,3 @@ tempfile = "3.12.0" ul-next = { version = "0.2.0", optional = true } url = "2.5.2" -[build-dependencies] -cmake = "0.1" diff --git a/examples/basic_browser.rs b/examples/basic_browser.rs index 03aa3f7..e306eb4 100644 --- a/examples/basic_browser.rs +++ b/examples/basic_browser.rs @@ -1,8 +1,7 @@ // Simple browser with familiar browser widget and the ultralight(webkit) webengine as a backend -use iced::{executor, Application, Command, Settings, Subscription, Theme}; +use iced::{Sandbox, Settings, Theme}; use iced_aw::BOOTSTRAP_FONT_BYTES; -use std::time::Duration; use icy_browser::{browser_widgets, BrowserWidget, Ultralight}; @@ -23,23 +22,19 @@ struct Browser { #[derive(Debug, Clone)] pub enum Message { BrowserWidget(browser_widgets::Message), - DoBrowserWork, } -impl Application for Browser { +impl Sandbox for Browser { type Message = Message; - type Executor = executor::Default; - type Flags = (); - type Theme = Theme; - fn new(_flags: Self::Flags) -> (Self, Command) { + fn new() -> Self { let widgets = BrowserWidget::new_with_ultralight() .with_tab_bar() .with_nav_bar() .with_browsesr_view() .build(); - (Self { widgets }, Command::none()) + Self { widgets } } fn title(&self) -> String { @@ -50,18 +45,12 @@ impl Application for Browser { Theme::Dark } - fn subscription(&self) -> Subscription { - iced::time::every(Duration::from_millis(100)).map(move |_| Message::DoBrowserWork) - } - - fn update(&mut self, message: Self::Message) -> Command { + fn update(&mut self, message: Self::Message) { match message { Message::BrowserWidget(msg) => { self.widgets.update(msg); } - Message::DoBrowserWork => self.widgets.update(browser_widgets::Message::DoWork), } - Command::none() } fn view(&self) -> iced::Element<'_, Self::Message> { diff --git a/src/engines/mod.rs b/src/engines/mod.rs index d71ff7b..9388e10 100644 --- a/src/engines/mod.rs +++ b/src/engines/mod.rs @@ -106,6 +106,22 @@ impl Tabs { } } + pub fn id_to_index(&self, id: u32) -> usize { + for (idx, tab) in self.tabs.iter().enumerate() { + if tab.id == id { + return idx; + } + } + panic!("Id: {} was not found", id); + } + + pub fn index_to_id(&self, index: usize) -> u32 { + self.tabs + .get(index) + .unwrap_or_else(|| panic!("Index {} was not found", index)) + .id + } + pub fn get_current_id(&self) -> u32 { self.current } @@ -125,7 +141,17 @@ impl Tabs { } pub fn remove(&mut self, id: u32) { - self.tabs.retain(|tab| tab.id != id) + // TODO: have list of prevous tabs instead + if self.current == id { + for tab in self.tabs.iter().rev() { + if tab.id != id { + self.current = tab.id; + break; + } + } + } + + self.tabs.retain(|tab| tab.id != id); } pub fn get_current(&self) -> &Tab { diff --git a/src/engines/ultralight.rs b/src/engines/ultralight.rs index 453271e..6a69c37 100644 --- a/src/engines/ultralight.rs +++ b/src/engines/ultralight.rs @@ -174,73 +174,63 @@ impl BrowserEngine for Ultralight { } fn new_tab(&mut self, url: &Url) -> u32 { - if self - .tabs - .tabs - .iter() - .filter(|tab| *tab.url.read().unwrap() == *url.as_ref()) - .count() - == 0 - { - let view = self - .renderer - .create_view(self.width, self.height, &self.view_config, None) - .unwrap(); - - let surface = view.surface().unwrap(); - view.load_url(url.as_ref()).unwrap(); - - // RGBA - debug_assert!(surface.row_bytes() / self.width == 4); - - // set callbacks - let site_url = Arc::new(RwLock::new(url.to_string())); - let cb_url = site_url.clone(); - view.set_change_url_callback(move |_view, url| { - *cb_url.write().unwrap() = url; - }); - - let title = Arc::new(RwLock::new(view.title().unwrap())); - let cb_title = title.clone(); - view.set_change_title_callback(move |_view, title| { - *cb_title.write().unwrap() = title; - }); - - let cursor = Arc::new(RwLock::new(mouse::Interaction::Idle)); - let cb_cursor = cursor.clone(); - view.set_change_cursor_callback(move |_view, cursor_update| { - *cb_cursor.write().unwrap() = match cursor_update { - Cursor::None => mouse::Interaction::Idle, - Cursor::Pointer => mouse::Interaction::Idle, - Cursor::Hand => mouse::Interaction::Pointer, - Cursor::Grab => mouse::Interaction::Grab, - Cursor::VerticalText => mouse::Interaction::Text, - Cursor::IBeam => mouse::Interaction::Text, - Cursor::Cross => mouse::Interaction::Crosshair, - Cursor::Wait => mouse::Interaction::Working, - Cursor::Grabbing => mouse::Interaction::Grab, - Cursor::NorthSouthResize => mouse::Interaction::ResizingVertically, - Cursor::EastWestResize => mouse::Interaction::ResizingHorizontally, - Cursor::NotAllowed => mouse::Interaction::NotAllowed, - Cursor::ZoomIn => mouse::Interaction::ZoomIn, - Cursor::ZoomOut => mouse::Interaction::ZoomIn, - _ => mouse::Interaction::Pointer, - }; - }); - - let tab_info = UltalightTabInfo { - surface, - view, - cursor, + let view = self + .renderer + .create_view(self.width, self.height, &self.view_config, None) + .unwrap(); + + let surface = view.surface().unwrap(); + view.load_url(url.as_ref()).unwrap(); + + // RGBA + debug_assert!(surface.row_bytes() / self.width == 4); + + // set callbacks + let site_url = Arc::new(RwLock::new(url.to_string())); + let cb_url = site_url.clone(); + view.set_change_url_callback(move |_view, url| { + *cb_url.write().unwrap() = url; + }); + + let title = Arc::new(RwLock::new(view.title().unwrap())); + let cb_title = title.clone(); + view.set_change_title_callback(move |_view, title| { + *cb_title.write().unwrap() = title; + }); + + let cursor = Arc::new(RwLock::new(mouse::Interaction::Idle)); + let cb_cursor = cursor.clone(); + view.set_change_cursor_callback(move |_view, cursor_update| { + *cb_cursor.write().unwrap() = match cursor_update { + Cursor::None => mouse::Interaction::Idle, + Cursor::Pointer => mouse::Interaction::Idle, + Cursor::Hand => mouse::Interaction::Pointer, + Cursor::Grab => mouse::Interaction::Grab, + Cursor::VerticalText => mouse::Interaction::Text, + Cursor::IBeam => mouse::Interaction::Text, + Cursor::Cross => mouse::Interaction::Crosshair, + Cursor::Wait => mouse::Interaction::Working, + Cursor::Grabbing => mouse::Interaction::Grab, + Cursor::NorthSouthResize => mouse::Interaction::ResizingVertically, + Cursor::EastWestResize => mouse::Interaction::ResizingHorizontally, + Cursor::NotAllowed => mouse::Interaction::NotAllowed, + Cursor::ZoomIn => mouse::Interaction::ZoomIn, + Cursor::ZoomOut => mouse::Interaction::ZoomIn, + _ => mouse::Interaction::Pointer, }; + }); - let tab = Tab::new(site_url, title, tab_info); - let id = tab.id; + let tab_info = UltalightTabInfo { + surface, + view, + cursor, + }; - self.tabs.insert(tab); - return id; - } - unreachable!(); + let tab = Tab::new(site_url, title, tab_info); + let id = tab.id; + + self.tabs.insert(tab); + return id; } fn goto_tab(&mut self, id: u32) { diff --git a/src/widgets/browser_widgets.rs b/src/widgets/browser_widgets.rs index 95c0cde..fe7d6e7 100644 --- a/src/widgets/browser_widgets.rs +++ b/src/widgets/browser_widgets.rs @@ -17,8 +17,8 @@ pub enum Message { Refresh, GoHome, GoUrl(String), - ChangeTab(u32), - CloseTab(u32), + ChangeTab(TabSelectionType), + CloseTab(TabSelectionType), CreateTab, UrlChanged(String), SendKeyboardEvent(keyboard::Event), @@ -27,6 +27,13 @@ pub enum Message { DoWork, } +#[derive(Debug, Clone)] +/// Allows different widgets to interact in their native way +pub enum TabSelectionType { + Id(u32), + Index(usize), +} + pub struct BrowserWidget { engine: Option, home: Url, @@ -101,7 +108,7 @@ where } pub fn build(self) -> Self { - assert!(!self.engine.is_none()); + assert!(self.engine.is_some()); let mut build = Self { engine: self.engine, @@ -130,6 +137,8 @@ where } pub fn update(&mut self, message: Message) { + self.engine().do_work(); + match message { Message::DoWork => self.engine().do_work(), Message::UpdateBounds(bounds) => { @@ -142,10 +151,20 @@ where Message::SendMouseEvent(point, event) => { self.engine_mut().handle_mouse_event(point, event); } - Message::ChangeTab(id) => self.engine_mut().goto_tab(id), - Message::CloseTab(id) => { - self.engine_mut().get_tabs_mut().remove(id); - } + Message::ChangeTab(index_type) => match index_type { + TabSelectionType::Id(id) => self.engine_mut().goto_tab(id), + TabSelectionType::Index(index) => { + let id = self.engine_mut().get_tabs().index_to_id(index); + self.engine_mut().goto_tab(id); + } + }, + Message::CloseTab(select_type) => match select_type { + TabSelectionType::Id(id) => self.engine_mut().get_tabs_mut().remove(id), + TabSelectionType::Index(index) => { + let id = self.engine_mut().get_tabs().index_to_id(index); + self.engine_mut().get_tabs_mut().remove(id); + } + }, Message::CreateTab => { self.url = self.home.to_string(); let home = self.home.clone(); @@ -191,9 +210,7 @@ where let mut column = column![]; if self.tab_bar { - let tabs = self.engine().get_tabs(); - let active_tab = self.engine().get_tabs().get_current().id(); - column = column.push(tab_bar(tabs, active_tab)) + column = column.push(tab_bar(self.engine().get_tabs())) } if self.nav_bar { column = column.push(nav_bar(&self.url)) diff --git a/src/widgets/tab_bar.rs b/src/widgets/tab_bar.rs index 43a833c..de4a5ef 100644 --- a/src/widgets/tab_bar.rs +++ b/src/widgets/tab_bar.rs @@ -3,20 +3,30 @@ use iced::{self, Element, Length}; use iced_aw::core::icons::bootstrap::{icon_to_text, Bootstrap}; use iced_aw::{TabBar as TB, TabLabel}; -use super::browser_widgets::Message; +use super::browser_widgets::{Message, TabSelectionType}; use crate::engines::Tabs; // helper function to create navigation bar -pub fn tab_bar(tabs: &Tabs, active_tab: u32) -> Element<'static, Message> { +pub fn tab_bar(tabs: &Tabs) -> Element<'static, Message> { + let current_id = tabs.get_current_id(); + let active_tab = tabs + .tabs() + .iter() + .position(|tab| tab.id() == current_id) + .expect("Failed to find tab with that id"); + let tab_bar = tabs .tabs() .iter() - .fold(TB::new(Message::ChangeTab), |tab_bar, tab| { - let id = tab_bar.size(); - tab_bar.push(id as u32, TabLabel::Text(tab.title())) - }) + .fold( + TB::new(|index| Message::ChangeTab(TabSelectionType::Index(index))), + |tab_bar, tab| { + let id = tab_bar.size(); + tab_bar.push(id, TabLabel::Text(tab.title())) + }, + ) .set_active_tab(&active_tab) - .on_close(Message::CloseTab) + .on_close(|index| Message::CloseTab(TabSelectionType::Index(index))) .tab_width(Length::Shrink) .spacing(5.0) .padding(5.0);