diff --git a/examples/browser.rs b/examples/browser.rs index c16d485..736c29c 100644 --- a/examples/browser.rs +++ b/examples/browser.rs @@ -1,9 +1,12 @@ //! This example showcases setting up a basic application and window, setting up some views to //! work with autolayout, and some basic ways to handle colors. -use cacao::webview::WebView; +use cacao::webview::{WebView, WebViewConfig, WebViewDelegate}; + +use cacao::input::{TextField, TextFieldDelegate}; use cacao::macos::{App, AppDelegate}; +use cacao::macos::toolbar::{Toolbar, ToolbarItem, ItemIdentifier, ToolbarDelegate}; use cacao::macos::menu::{Menu, MenuItem}; use cacao::macos::window::{Window, WindowConfig, WindowDelegate}; @@ -39,7 +42,6 @@ impl AppDelegate for BasicApp { MenuItem::SelectAll ]), - // Sidebar option is 11.0+ only. Menu::new("View", vec![ MenuItem::EnterFullScreen ]), @@ -59,9 +61,50 @@ impl AppDelegate for BasicApp { } } +pub struct URLBar; + +impl TextFieldDelegate for URLBar { + const NAME: &'static str = "URLBar"; +} + +struct BrowserToolbar { + url_bar: TextField +} + +impl BrowserToolbar { + pub fn new() -> Self { + BrowserToolbar { + url_bar: TextField::with(URLBar) + } + } +} + +impl ToolbarDelegate for BrowserToolbar { + const NAME: &'static str = "BrowserToolbar"; + + fn allowed_item_identifiers(&self) -> Vec { vec![] } + fn default_item_identifiers(&self) -> Vec { vec![] } + + fn item_for(&self, _identifier: &str) -> &ToolbarItem { std::unreachable!(); } +} + #[derive(Default)] +pub struct WebViewInstance; + +impl WebViewDelegate for WebViewInstance {} + struct AppWindow { - content: WebView + toolbar: Toolbar, + content: WebView +} + +impl AppWindow { + pub fn new() -> Self { + AppWindow { + toolbar: Toolbar::new("com.example.BrowserToolbar", BrowserToolbar::new()), + content: WebView::with(WebViewConfig::default(), WebViewInstance::default()) + } + } } impl WindowDelegate for AppWindow { @@ -71,6 +114,7 @@ impl WindowDelegate for AppWindow { window.set_title("Browser Example"); window.set_minimum_content_size(400., 400.); + window.set_toolbar(&self.toolbar); window.set_content_view(&self.content); self.content.load_url("https://www.duckduckgo.com/"); @@ -79,6 +123,6 @@ impl WindowDelegate for AppWindow { fn main() { App::new("com.test.window", BasicApp { - window: Window::with(WindowConfig::default(), AppWindow::default()) + window: Window::with(WindowConfig::default(), AppWindow::new()) }).run(); } diff --git a/examples/text_input.rs b/examples/text_input.rs new file mode 100644 index 0000000..d6994b2 --- /dev/null +++ b/examples/text_input.rs @@ -0,0 +1,122 @@ +//! This example showcases setting up a basic application and window, setting up some views to +//! work with autolayout, and some basic ways to handle colors. + +use cacao::layout::{Layout, LayoutConstraint}; +use cacao::input::{TextField, TextFieldDelegate}; +use cacao::view::View; + +use cacao::macos::{App, AppDelegate}; +use cacao::macos::menu::{Menu, MenuItem}; +use cacao::macos::window::{Window, WindowConfig, WindowDelegate}; + +struct BasicApp { + window: Window +} + +impl AppDelegate for BasicApp { + fn did_finish_launching(&self) { + App::set_menu(vec![ + Menu::new("", vec![ + MenuItem::Services, + MenuItem::Separator, + MenuItem::Hide, + MenuItem::HideOthers, + MenuItem::ShowAll, + MenuItem::Separator, + MenuItem::Quit + ]), + + Menu::new("File", vec![ + MenuItem::CloseWindow + ]), + + Menu::new("Edit", vec![ + MenuItem::Undo, + MenuItem::Redo, + MenuItem::Separator, + MenuItem::Cut, + MenuItem::Copy, + MenuItem::Paste, + MenuItem::Separator, + MenuItem::SelectAll + ]), + + // Sidebar option is 11.0+ only. + Menu::new("View", vec![ + MenuItem::EnterFullScreen + ]), + + Menu::new("Window", vec![ + MenuItem::Minimize, + MenuItem::Zoom, + MenuItem::Separator, + MenuItem::new("Bring All to Front") + ]), + + Menu::new("Help", vec![]) + ]); + + App::activate(); + self.window.show(); + } +} + +#[derive(Debug, Default)] +pub struct ConsoleLogger; + +impl TextFieldDelegate for ConsoleLogger { + const NAME: &'static str = "ConsoleLogger"; + + fn text_should_begin_editing(&self, value: &str) -> bool { + println!("Should begin with value: {}", value); + true + } + + fn text_did_change(&self, value: &str) { + println!("Did change to: {}", value); + } + + + fn text_did_end_editing(&self, value: &str) { + println!("Ended: {}", value); + } +} + +#[derive(Debug)] +struct AppWindow { + input: TextField, + content: View +} + +impl AppWindow { + pub fn new() -> Self { + AppWindow { + input: TextField::with(ConsoleLogger), + content: View::new(), + } + } +} + +impl WindowDelegate for AppWindow { + const NAME: &'static str = "WindowDelegate"; + + fn did_load(&mut self, window: Window) { + window.set_title("Input Logger Example"); + window.set_minimum_content_size(300., 300.); + + self.content.add_subview(&self.input); + window.set_content_view(&self.content); + + LayoutConstraint::activate(&[ + self.input.center_x.constraint_equal_to(&self.content.center_x), + self.input.center_y.constraint_equal_to(&self.content.center_y), + self.input.width.constraint_equal_to_constant(280.) + ]); + } +} + +fn main() { + App::new("com.test.window", BasicApp { + window: Window::with(WindowConfig::default(), AppWindow::new()) + }).run(); +} diff --git a/src/input/macos.rs b/src/input/macos.rs index db29bb9..59bfebd 100644 --- a/src/input/macos.rs +++ b/src/input/macos.rs @@ -13,19 +13,19 @@ use crate::utils::load; /// Called when editing this text field has ended (e.g. user pressed enter). extern "C" fn text_did_end_editing(this: &mut Object, _: Sel, _info: id) { let view = load::(this, TEXTFIELD_DELEGATE_PTR); - let s = NSString::from_retained(unsafe { msg_send![this, stringValue] }); + let s = NSString::retain(unsafe { msg_send![this, stringValue] }); view.text_did_end_editing(s.to_str()); } extern "C" fn text_did_begin_editing(this: &mut Object, _: Sel, _info: id) { let view = load::(this, TEXTFIELD_DELEGATE_PTR); - let s = NSString::from_retained(unsafe { msg_send![this, stringValue] }); + let s = NSString::retain(unsafe { msg_send![this, stringValue] }); view.text_did_begin_editing(s.to_str()); } extern "C" fn text_did_change(this: &mut Object, _: Sel, _info: id) { let view = load::(this, TEXTFIELD_DELEGATE_PTR); - let s = NSString::from_retained(unsafe { msg_send![this, stringValue] }); + let s = NSString::retain(unsafe { msg_send![this, stringValue] }); view.text_did_change(s.to_str()); } @@ -35,7 +35,7 @@ extern "C" fn text_should_begin_editing( _info: id, ) -> BOOL { let view = load::(this, TEXTFIELD_DELEGATE_PTR); - let s = NSString::from_retained(unsafe { msg_send![this, stringValue] }); + let s = NSString::retain(unsafe { msg_send![this, stringValue] }); match view.text_should_begin_editing(s.to_str()) { true => YES,