cacao/examples/browser/toolbar.rs
Mads Marquart 094ed59a04
Initial conversion to objc2 (#30)
* Use objc2

* Replace `objc_id`

* Remove sel_impl import

* Fix `add_method` calls

* Fix accessing raw FFI functions

* Fix Encode impl

* Fix message sends arguments that do not implement `Encode`

* Use immutable reference in a few places where now necessary

See https://github.com/madsmtm/objc2/pull/150 for a bit of background

* Add a few Send + Sync bounds where examples require it

This is something we'll need to look into properly

* Use `&'static Class` instead of `*const Class`

Safer and more ergonomic. Also required for `msg_send_id!` macro

* Use msg_send_id! and rc::Id

* Update objc2 to v0.3.0-beta.2

* Replace `BOOL` with `Bool` when declaring delegates

This makes cacao compile on Aarch64 again

* Remove a few impossible to use correctly `into_inner` functions

These consumed `self`, and hence also dropped `Id` variable that was responsible for keeping the returned pointer alive

* Remove a few impossible to use correctly `From` implementations

* Quickly fix UB with using BACKGROUND_COLOR ivar

* Fix double-freeing of windows

* Fix double freeing of strings

* Fix a few remaining double-frees
2023-09-11 09:59:21 -07:00

107 lines
3.1 KiB
Rust

use cacao::objc::{msg_send, sel};
use cacao::button::Button;
use cacao::input::{TextField, TextFieldDelegate};
use cacao::appkit::toolbar::{ItemIdentifier, Toolbar, ToolbarDelegate, ToolbarDisplayMode, ToolbarItem};
use super::Action;
const BACK_BUTTON: &str = "BackButton";
const FWDS_BUTTON: &str = "FwdsButton";
const URL_BAR: &str = "URLBar";
#[derive(Debug)]
pub struct URLBar;
impl TextFieldDelegate for URLBar {
const NAME: &'static str = "URLBar";
fn text_did_end_editing(&self, value: &str) {
Action::Load(value.to_string()).dispatch();
}
}
#[derive(Debug)]
pub struct BrowserToolbar {
back_item: ToolbarItem,
forwards_item: ToolbarItem,
url_bar: TextField<URLBar>,
url_bar_item: ToolbarItem
}
impl BrowserToolbar {
pub fn new() -> Self {
let back_button = Button::new("Back");
let mut back_item = ToolbarItem::new(BACK_BUTTON);
back_item.set_button(back_button);
back_item.set_action(|_| Action::Back.dispatch());
let forwards_button = Button::new("Forwards");
let mut forwards_item = ToolbarItem::new(FWDS_BUTTON);
forwards_item.set_button(forwards_button);
forwards_item.set_action(|_| Action::Forwards.dispatch());
let url_bar = TextField::with(URLBar);
let url_bar_item = ToolbarItem::new(URL_BAR);
// We cheat for now to link these, as there's no API for Toolbar yet
// to support arbitrary view types. The framework is designed to support this kind of
// cheating, though: it's not outlandish to need to just manage things yourself when it
// comes to Objective-C/AppKit sometimes.
//
// As long as we keep hold of things here and they all drop together, it's relatively safe.
url_bar.objc.with_mut(|obj| unsafe {
let _: () = msg_send![&*url_bar_item.objc, setView:&*obj];
});
BrowserToolbar {
back_item,
forwards_item,
url_bar,
url_bar_item
}
}
pub fn set_url(&self, url: &str) {
self.url_bar.set_text(url);
}
fn item_identifiers(&self) -> Vec<ItemIdentifier> {
vec![
ItemIdentifier::Custom(BACK_BUTTON),
ItemIdentifier::Custom(FWDS_BUTTON),
ItemIdentifier::Space,
ItemIdentifier::Custom(URL_BAR),
ItemIdentifier::Space,
]
}
}
impl ToolbarDelegate for BrowserToolbar {
const NAME: &'static str = "BrowserToolbar";
fn did_load(&mut self, toolbar: Toolbar) {
toolbar.set_display_mode(ToolbarDisplayMode::IconOnly);
}
fn allowed_item_identifiers(&self) -> Vec<ItemIdentifier> {
self.item_identifiers()
}
fn default_item_identifiers(&self) -> Vec<ItemIdentifier> {
self.item_identifiers()
}
fn item_for(&self, identifier: &str) -> &ToolbarItem {
match identifier {
BACK_BUTTON => &self.back_item,
FWDS_BUTTON => &self.forwards_item,
URL_BAR => &self.url_bar_item,
_ => {
std::unreachable!();
}
}
}
}