update actions

This commit is contained in:
yggverse 2024-11-11 05:11:48 +02:00
parent a5fc2a7475
commit a6ef61486d
24 changed files with 190 additions and 294 deletions

View File

@ -35,7 +35,7 @@ impl Browser {
// Init widget // Init widget
let widget = Rc::new(Widget::new( let widget = Rc::new(Widget::new(
window.gobject(), window.widget().gobject(),
&[ &[
// Connect action groups (to apply accels) // Connect action groups (to apply accels)
( (
@ -48,11 +48,6 @@ impl Browser {
window.action().id(), window.action().id(),
window.action().gobject().clone(), window.action().gobject().clone(),
), ),
(
// Tab
window.tab().action().id(),
window.tab().action().gobject().clone(),
),
], ],
)); ));
@ -60,7 +55,7 @@ impl Browser {
action.about().connect_activate({ action.about().connect_activate({
let window = window.clone(); let window = window.clone();
move || { move || {
About::new().present(Some(window.gobject())); About::new().present(Some(window.widget().gobject()));
} }
}); });

View File

@ -12,13 +12,12 @@ use tab::Tab;
use widget::Widget; use widget::Widget;
use crate::app::browser::action::Action as BrowserAction; use crate::app::browser::action::Action as BrowserAction;
use gtk::{glib::GString, Box}; use gtk::glib::GString;
use std::rc::Rc; use std::rc::Rc;
pub struct Window { pub struct Window {
//header: Rc<Header>,
tab: Rc<Tab>,
action: Rc<Action>, action: Rc<Action>,
tab: Rc<Tab>,
widget: Rc<Widget>, widget: Rc<Widget>,
} }
@ -33,10 +32,10 @@ impl Window {
// Init components // Init components
let tab = Rc::new(Tab::new(browser_action.clone(), action.clone())); let tab = Rc::new(Tab::new(browser_action.clone(), action.clone()));
let header = Header::new(browser_action, action.clone(), tab.gobject()); let header = Header::new(browser_action, action.clone(), tab.widget().gobject());
// GTK // GTK
let widget = Rc::new(Widget::new(header.gobject(), tab.gobject())); let widget = Rc::new(Widget::new(header.gobject(), tab.widget().gobject()));
// Init events // Init events
action.append().connect_activate({ action.append().connect_activate({
@ -91,9 +90,8 @@ impl Window {
// Init struct // Init struct
Self { Self {
//header,
tab,
action, action,
tab,
widget, widget,
} }
} }
@ -163,12 +161,8 @@ impl Window {
&self.action &self.action
} }
pub fn tab(&self) -> &Rc<Tab> { pub fn widget(&self) -> &Rc<Widget> {
&self.tab &self.widget
}
pub fn gobject(&self) -> &Box {
self.widget.gobject()
} }
} }

View File

@ -1,10 +1,8 @@
mod action;
mod database; mod database;
mod item; mod item;
mod menu; mod menu;
mod widget; mod widget;
use action::Action;
use database::Database; use database::Database;
use item::Item; use item::Item;
use menu::Menu; use menu::Menu;
@ -12,7 +10,6 @@ use widget::Widget;
use crate::app::browser::action::Action as BrowserAction; use crate::app::browser::action::Action as BrowserAction;
use crate::app::browser::window::action::Action as WindowAction; use crate::app::browser::window::action::Action as WindowAction;
use adw::TabView;
use gtk::{ use gtk::{
glib::{GString, Propagation}, glib::{GString, Propagation},
prelude::WidgetExt, prelude::WidgetExt,
@ -22,22 +19,16 @@ use std::{cell::RefCell, collections::HashMap, rc::Rc};
// Main // Main
pub struct Tab { pub struct Tab {
// Actions
browser_action: Rc<BrowserAction>, browser_action: Rc<BrowserAction>,
window_action: Rc<WindowAction>, window_action: Rc<WindowAction>,
// Dynamically allocated reference index
index: Rc<RefCell<HashMap<GString, Rc<Item>>>>, index: Rc<RefCell<HashMap<GString, Rc<Item>>>>,
action: Rc<Action>,
widget: Rc<Widget>, widget: Rc<Widget>,
} }
impl Tab { impl Tab {
// Construct // Construct
pub fn new(browser_action: Rc<BrowserAction>, window_action: Rc<WindowAction>) -> Self { pub fn new(browser_action: Rc<BrowserAction>, window_action: Rc<WindowAction>) -> Self {
// Init local actions // Init empty HashMap index
let action = Rc::new(Action::new());
// Init empty HashMap index as no tabs appended yet
let index: Rc<RefCell<HashMap<GString, Rc<Item>>>> = Rc::new(RefCell::new(HashMap::new())); let index: Rc<RefCell<HashMap<GString, Rc<Item>>>> = Rc::new(RefCell::new(HashMap::new()));
// Init context menu // Init context menu
@ -98,29 +89,11 @@ impl Tab {
} }
}); });
action.open().connect_activate({
let index = index.clone();
let widget = widget.clone();
move |request| {
if let Some(value) = request {
if let Some(page) = widget.page(None) {
if let Some(id) = page.keyword() {
if let Some(item) = index.borrow().get(&id) {
item.set_page_navigation_request_text(value.as_str());
item.page().reload();
}
}
}
}
}
}); // @TODO fix new item on middle click
// Return activated `Self` // Return activated `Self`
Self { Self {
browser_action, browser_action,
window_action, window_action,
index, index,
action,
widget, widget,
} }
} }
@ -128,19 +101,20 @@ impl Tab {
// Actions // Actions
pub fn append(&self, position: Option<i32>) -> Rc<Item> { pub fn append(&self, position: Option<i32>) -> Rc<Item> {
// Init new tab item // Init new tab item
let item = Item::new_rc( let item = Rc::new(Item::new(
self.gobject(), self.widget.gobject(),
self.browser_action.clone(), self.browser_action.clone(),
self.window_action.clone(), self.window_action.clone(),
self.action.clone(),
// Options // Options
position, position,
false, false,
true, true,
); ));
// Register dynamically created tab components in the HashMap index // Register dynamically created tab components in the HashMap index
self.index.borrow_mut().insert(item.id(), item.clone()); self.index
.borrow_mut()
.insert(item.id().clone(), item.clone());
item.page() item.page()
.navigation() .navigation()
@ -220,8 +194,10 @@ impl Tab {
item.update(); item.update();
// Update tab title on loading indicator inactive // Update tab title on loading indicator inactive
if !item.page_is_loading() { if !item.page().is_loading() {
item.gobject().set_title(item.page_meta_title().as_str()) item.widget()
.gobject()
.set_title(item.page().meta().title().as_str())
} }
} }
// Update all tabs on ID not found @TODO change initial update method // Update all tabs on ID not found @TODO change initial update method
@ -231,8 +207,10 @@ impl Tab {
item.update(); item.update();
// Update tab title on loading indicator inactive // Update tab title on loading indicator inactive
if !item.page_is_loading() { if !item.page().is_loading() {
item.gobject().set_title(item.page_meta_title().as_str()) item.widget()
.gobject()
.set_title(item.page().meta().title().as_str())
} }
} }
} }
@ -273,17 +251,18 @@ impl Tab {
Ok(records) => { Ok(records) => {
for record in records { for record in records {
match Item::restore( match Item::restore(
self.gobject(), self.widget.gobject(),
transaction, transaction,
&record.id, &record.id,
self.browser_action.clone(), self.browser_action.clone(),
self.window_action.clone(), self.window_action.clone(),
self.action.clone(),
) { ) {
Ok(items) => { Ok(items) => {
for item in items { for item in items {
// Register dynamically created tab item in the HashMap index // Register dynamically created tab item in the HashMap index
self.index.borrow_mut().insert(item.id(), item.clone()); self.index
.borrow_mut()
.insert(item.id().clone(), item.clone());
} }
} }
Err(e) => return Err(e.to_string()), Err(e) => return Err(e.to_string()),
@ -311,9 +290,9 @@ impl Tab {
item.save( item.save(
transaction, transaction,
&id, &id,
&self.widget.gobject().page_position(item.gobject()), &self.widget.gobject().page_position(item.widget().gobject()),
&item.gobject().is_pinned(), &item.widget().gobject().is_pinned(),
&item.gobject().is_selected(), &item.widget().gobject().is_selected(),
)?; )?;
} }
} }
@ -334,12 +313,8 @@ impl Tab {
// Getters // Getters
pub fn action(&self) -> &Rc<Action> { pub fn widget(&self) -> &Rc<Widget> {
&self.action &self.widget
}
pub fn gobject(&self) -> &TabView {
self.widget.gobject()
} }
} }

View File

@ -1,15 +1,15 @@
mod action;
mod database; mod database;
mod page; mod page;
mod widget; mod widget;
use action::Action;
use database::Database; use database::Database;
use page::Page; use page::Page;
use widget::Widget; use widget::Widget;
use crate::app::browser::action::Action as BrowserAction; use crate::app::browser::{window::Action as WindowAction, Action as BrowserAction};
use crate::app::browser::window::action::Action as WindowAction; use adw::TabView;
use crate::app::browser::window::tab::action::Action as TabAction;
use adw::{TabPage, TabView};
use gtk::{ use gtk::{
glib::{uuid_string_random, GString}, glib::{uuid_string_random, GString},
prelude::EditableExt, prelude::EditableExt,
@ -22,47 +22,70 @@ pub struct Item {
// useful as widget name in GTK actions callback // useful as widget name in GTK actions callback
id: GString, id: GString,
// Components // Components
action: Rc<Action>,
page: Rc<Page>, page: Rc<Page>,
widget: Rc<Widget>, widget: Rc<Widget>,
} }
impl Item { impl Item {
// Construct // Construct
pub fn new_rc( pub fn new(
tab_view: &TabView, tab_view: &TabView,
// Actions // Actions
browser_action: Rc<BrowserAction>, browser_action: Rc<BrowserAction>,
window_action: Rc<WindowAction>, window_action: Rc<WindowAction>,
tab_action: Rc<TabAction>,
// Options // Options
position: Option<i32>, position: Option<i32>,
is_pinned: bool, is_pinned: bool,
is_selected: bool, is_selected: bool,
) -> Rc<Self> { ) -> Self {
// Generate unique ID for new page components // Generate unique ID for new page components
let id = uuid_string_random(); let id = uuid_string_random();
// Init components // Init components
let page = Page::new_rc(
let action = Rc::new(Action::new());
let page = Rc::new(Page::new(
id.clone(), id.clone(),
// Actions
browser_action, browser_action,
window_action, window_action,
tab_action, action.clone(),
); ));
let widget = Rc::new(Widget::new( let widget = Rc::new(Widget::new(
id.as_str(), id.as_str(),
tab_view, tab_view,
page.gobject(), page.widget().gobject(),
None, None,
position, position,
is_pinned, is_pinned,
is_selected, is_selected,
)); // @TODO ));
// Return struct // Init events
Rc::new(Self { id, page, widget })
action.load().connect_activate({
let page = page.clone();
move |request| {
if let Some(text) = request {
page.navigation()
.request()
.widget()
.gobject()
.set_text(&text);
}
page.load(true);
}
});
// Done
Self {
id,
action,
page,
widget,
}
} }
// Actions // Actions
@ -71,7 +94,7 @@ impl Item {
self.page.update(); self.page.update();
// Update tab loading indicator // Update tab loading indicator
self.widget.gobject().set_loading(self.page_is_loading()); self.widget.gobject().set_loading(self.page().is_loading());
} }
pub fn clean( pub fn clean(
@ -107,7 +130,6 @@ impl Item {
// Actions // Actions
browser_action: Rc<BrowserAction>, browser_action: Rc<BrowserAction>,
window_action: Rc<WindowAction>, window_action: Rc<WindowAction>,
tab_action: Rc<TabAction>,
) -> Result<Vec<Rc<Item>>, String> { ) -> Result<Vec<Rc<Item>>, String> {
let mut items = Vec::new(); let mut items = Vec::new();
@ -115,17 +137,16 @@ impl Item {
Ok(records) => { Ok(records) => {
for record in records { for record in records {
// Construct new item object // Construct new item object
let item = Item::new_rc( let item = Rc::new(Item::new(
tab_view, tab_view,
// Actions // Actions
browser_action.clone(), browser_action.clone(),
window_action.clone(), window_action.clone(),
tab_action.clone(),
// Options // Options
None, None,
record.is_pinned, record.is_pinned,
record.is_selected, record.is_selected,
); ));
// Delegate restore action to the item childs // Delegate restore action to the item childs
item.page.restore(transaction, &record.id)?; item.page.restore(transaction, &record.id)?;
@ -169,36 +190,18 @@ impl Item {
Ok(()) Ok(())
} }
// Setters
pub fn set_page_navigation_request_text(&self, value: &str) {
self.page
.navigation()
.request()
.widget()
.gobject()
.set_text(value);
}
// Getters // Getters
pub fn id(&self) -> GString { pub fn id(&self) -> &GString {
self.id.clone() &self.id
} }
pub fn page(&self) -> &Rc<Page> { pub fn page(&self) -> &Rc<Page> {
&self.page &self.page
} }
pub fn page_is_loading(&self) -> bool { pub fn widget(&self) -> &Rc<Widget> {
self.page.is_loading() &self.widget
}
pub fn page_meta_title(&self) -> GString {
self.page.meta_title()
}
pub fn gobject(&self) -> &TabPage {
self.widget.gobject()
} }
} }

View File

@ -1,6 +1,5 @@
mod open; mod load;
use load::Load;
use open::Open;
use gtk::{ use gtk::{
gio::SimpleActionGroup, gio::SimpleActionGroup,
@ -12,7 +11,7 @@ use std::rc::Rc;
/// [SimpleActionGroup](https://docs.gtk.org/gio/class.SimpleActionGroup.html) wrapper for `Browser` actions /// [SimpleActionGroup](https://docs.gtk.org/gio/class.SimpleActionGroup.html) wrapper for `Browser` actions
pub struct Action { pub struct Action {
// Actions // Actions
open: Rc<Open>, load: Rc<Load>,
// Group // Group
id: GString, id: GString,
gobject: SimpleActionGroup, gobject: SimpleActionGroup,
@ -24,7 +23,7 @@ impl Action {
/// Create new `Self` /// Create new `Self`
pub fn new() -> Self { pub fn new() -> Self {
// Init actions // Init actions
let open = Rc::new(Open::new()); let load = Rc::new(Load::new());
// Generate unique group ID // Generate unique group ID
let id = uuid_string_random(); let id = uuid_string_random();
@ -33,17 +32,17 @@ impl Action {
let gobject = SimpleActionGroup::new(); let gobject = SimpleActionGroup::new();
// Add action to given group // Add action to given group
gobject.add_action(open.gobject()); gobject.add_action(load.gobject());
// Done // Done
Self { open, id, gobject } Self { load, id, gobject }
} }
// Getters // Getters
/// Get reference `Open` action /// Get reference to `Load` action
pub fn open(&self) -> &Rc<Open> { pub fn load(&self) -> &Rc<Load> {
&self.open &self.load
} }
/// Get auto-generated name for action group /// Get auto-generated name for action group

View File

@ -4,12 +4,12 @@ use gtk::{
prelude::{ActionExt, StaticVariantType, ToVariant}, prelude::{ActionExt, StaticVariantType, ToVariant},
}; };
/// [SimpleAction](https://docs.gtk.org/gio/class.SimpleAction.html) wrapper for `Open` action of `Browser` group /// [SimpleAction](https://docs.gtk.org/gio/class.SimpleAction.html) wrapper for `Load` action of `Item` group
pub struct Open { pub struct Load {
gobject: SimpleAction, gobject: SimpleAction,
} }
impl Open { impl Load {
// Constructors // Constructors
/// Create new `Self` /// Create new `Self`
@ -23,9 +23,9 @@ impl Open {
/// Emit [activate](https://docs.gtk.org/gio/signal.SimpleAction.activate.html) signal /// Emit [activate](https://docs.gtk.org/gio/signal.SimpleAction.activate.html) signal
/// with formatted for this action [Variant](https://docs.gtk.org/glib/struct.Variant.html) value /// with formatted for this action [Variant](https://docs.gtk.org/glib/struct.Variant.html) value
pub fn activate(&self, tab_item_id: Option<&str>) { pub fn activate(&self, request: Option<&str>) {
self.gobject.activate(Some( self.gobject.activate(Some(
&match tab_item_id { &match request {
Some(value) => String::from(value), Some(value) => String::from(value),
None => String::new(), None => String::new(),
} }
@ -39,14 +39,14 @@ impl Open {
/// [SimpleAction::activate](https://docs.gtk.org/gio/signal.SimpleAction.activate.html) signal /// [SimpleAction::activate](https://docs.gtk.org/gio/signal.SimpleAction.activate.html) signal
pub fn connect_activate(&self, callback: impl Fn(Option<GString>) + 'static) { pub fn connect_activate(&self, callback: impl Fn(Option<GString>) + 'static) {
self.gobject.connect_activate(move |_, variant| { self.gobject.connect_activate(move |_, variant| {
let tab_item_id = variant let request = variant
.expect("Variant required to call this action") .expect("Parameter value required")
.get::<String>() .get::<String>()
.expect("Parameter type does not match `String`"); .expect("Parameter type does not match `String`");
callback(match tab_item_id.is_empty() { callback(match request.is_empty() {
true => None, true => None,
false => Some(tab_item_id.into()), false => Some(request.into()),
}) })
}); });
} }
@ -57,10 +57,4 @@ impl Open {
pub fn gobject(&self) -> &SimpleAction { pub fn gobject(&self) -> &SimpleAction {
&self.gobject &self.gobject
} }
/* @TODO not in use
/// Get auto-generated [action name](https://docs.gtk.org/gio/property.SimpleAction.name.html)
pub fn id(&self) -> GString {
self.gobject.name()
} */
} }

View File

@ -12,24 +12,18 @@ use meta::{Meta, Status};
use navigation::Navigation; use navigation::Navigation;
use widget::Widget; use widget::Widget;
use crate::app::browser::action::Action as BrowserAction; use crate::app::browser::{
use crate::app::browser::window::action::Action as WindowAction; window::{tab::item::Action as TabAction, Action as WindowAction},
use crate::app::browser::window::tab::action::Action as TabAction; Action as BrowserAction,
};
use gtk::{ use gtk::{
gdk_pixbuf::Pixbuf, gdk_pixbuf::Pixbuf,
gio::{ gio::{Cancellable, SocketClient, SocketClientEvent, SocketProtocol, TlsCertificateFlags},
Cancellable, SimpleAction, SocketClient, SocketClientEvent, SocketProtocol,
TlsCertificateFlags,
},
glib::{ glib::{
gformat, uuid_string_random, Bytes, GString, Priority, Regex, RegexCompileFlags, gformat, Bytes, GString, Priority, Regex, RegexCompileFlags, RegexMatchFlags, Uri,
RegexMatchFlags, Uri, UriFlags, UriHideFlags, UriFlags, UriHideFlags,
}, },
prelude::{ prelude::{CancellableExt, EditableExt, IOStreamExt, OutputStreamExt, SocketClientExt},
ActionExt, CancellableExt, EditableExt, IOStreamExt, OutputStreamExt, SocketClientExt,
StaticVariantType,
},
Box,
}; };
use sqlite::Transaction; use sqlite::Transaction;
use std::{cell::RefCell, rc::Rc, time::Duration}; use std::{cell::RefCell, rc::Rc, time::Duration};
@ -39,47 +33,38 @@ pub struct Page {
cancellable: RefCell<Cancellable>, cancellable: RefCell<Cancellable>,
// Actions // Actions
browser_action: Rc<BrowserAction>, browser_action: Rc<BrowserAction>,
window_action: Rc<WindowAction>,
tab_action: Rc<TabAction>, tab_action: Rc<TabAction>,
action_page_load: SimpleAction,
// Components // Components
navigation: Rc<Navigation>, navigation: Rc<Navigation>,
content: Rc<Content>, content: Rc<Content>,
input: Rc<Input>, input: Rc<Input>,
// Extras
meta: Rc<Meta>, meta: Rc<Meta>,
// GTK
widget: Rc<Widget>, widget: Rc<Widget>,
} }
impl Page { impl Page {
// Constructors // Constructors
/// Create new activated `Rc<Self>` pub fn new(
pub fn new_rc(
id: GString, id: GString,
browser_action: Rc<BrowserAction>, browser_action: Rc<BrowserAction>,
window_action: Rc<WindowAction>, window_action: Rc<WindowAction>,
tab_action: Rc<TabAction>, tab_action: Rc<TabAction>,
) -> Rc<Self> { ) -> Self {
// Init local actions
let action_page_load = SimpleAction::new(&uuid_string_random(), None);
let action_page_open =
SimpleAction::new(&uuid_string_random(), Some(&String::static_variant_type()));
// Init components // Init components
let content = Rc::new(Content::new(tab_action.clone(), action_page_open.clone())); let content = Rc::new(Content::new(window_action.clone(), tab_action.clone()));
let navigation = Rc::new(Navigation::new( let navigation = Rc::new(Navigation::new(
browser_action.clone(), browser_action.clone(),
window_action.clone(), window_action.clone(),
action_page_open.clone(), tab_action.clone(),
)); ));
let input = Rc::new(Input::new()); let input = Rc::new(Input::new());
let widget = Rc::new(Widget::new( let widget = Rc::new(Widget::new(
&id, &id,
action_page_open.clone(),
navigation.widget().gobject(), navigation.widget().gobject(),
content.gobject(), content.gobject(),
input.gobject(), input.gobject(),
@ -87,48 +72,21 @@ impl Page {
let meta = Rc::new(Meta::new(Status::New, gformat!("New page"))); let meta = Rc::new(Meta::new(Status::New, gformat!("New page")));
// Init `Self` // Done
let this = Rc::new(Self { Self {
cancellable: RefCell::new(Cancellable::new()), cancellable: RefCell::new(Cancellable::new()),
id, id,
// Actions // Actions
browser_action, browser_action,
window_action,
tab_action, tab_action,
action_page_load: action_page_load.clone(),
// Components // Components
content, content,
navigation, navigation,
input, input,
// Extras
meta, meta,
// GTK
widget, widget,
});
// Init events
action_page_load.connect_activate({
let this = this.clone();
move |_, _| this.load(false)
});
action_page_open.connect_activate({
let this = this.clone();
move |_, request| {
// Set request value from action parameter
this.navigation().request().widget().gobject().set_text(
&request
.expect("Parameter required for this action")
.get::<String>()
.expect("Parameter does not match `String`"),
);
// Reload page
this.load(true);
} }
});
// Return activated `Self`
this
} }
// Actions // Actions
@ -138,7 +96,7 @@ impl Page {
pub fn home(&self) { pub fn home(&self) {
if let Some(url) = self.navigation.home().url() { if let Some(url) = self.navigation.home().url() {
// Update with history record // Update with history record
self.tab_action.open().activate(Some(&url)); self.tab_action.load().activate(Some(&url));
} }
} }
@ -432,21 +390,16 @@ impl Page {
} }
} }
pub fn meta_title(&self) -> GString {
self.meta.title()
}
/*
pub fn meta(&self) -> &Rc<Meta> { pub fn meta(&self) -> &Rc<Meta> {
&self.meta &self.meta
} */ }
pub fn navigation(&self) -> &Rc<Navigation> { pub fn navigation(&self) -> &Rc<Navigation> {
&self.navigation &self.navigation
} }
pub fn gobject(&self) -> &Box { pub fn widget(&self) -> &Rc<Widget> {
self.widget.gobject() &self.widget
} }
// Private helpers @TODO move outside // Private helpers @TODO move outside
@ -457,7 +410,6 @@ impl Page {
// Init shared objects (async) // Init shared objects (async)
let cancellable = self.cancellable.borrow().clone(); let cancellable = self.cancellable.borrow().clone();
let update = self.browser_action.update().clone(); let update = self.browser_action.update().clone();
let action_page_load = self.action_page_load.clone();
let tab_action = self.tab_action.clone(); let tab_action = self.tab_action.clone();
let content = self.content.clone(); let content = self.content.clone();
let id = self.id.clone(); let id = self.id.clone();
@ -799,7 +751,7 @@ impl Page {
.set_title("Redirect"); .set_title("Redirect");
// Reload page to apply redirection // Reload page to apply redirection
action_page_load.activate(None); tab_action.load().activate(None);
} }
}, },
Err(reason) => { Err(reason) => {

View File

@ -6,10 +6,9 @@ use image::Image;
use status::Status; use status::Status;
use text::Text; use text::Text;
use crate::app::browser::window::tab::action::Action as TabAction; use crate::app::browser::window::{tab::item::Action as TabAction, Action as WindowAction};
use gtk::{ use gtk::{
gdk_pixbuf::Pixbuf, gdk_pixbuf::Pixbuf,
gio::SimpleAction,
glib::Uri, glib::Uri,
prelude::{BoxExt, WidgetExt}, prelude::{BoxExt, WidgetExt},
Box, Orientation, Box, Orientation,
@ -17,22 +16,20 @@ use gtk::{
use std::{rc::Rc, time::Duration}; use std::{rc::Rc, time::Duration};
pub struct Content { pub struct Content {
// GTK window_action: Rc<WindowAction>,
gobject: Box,
// Actions
tab_action: Rc<TabAction>, tab_action: Rc<TabAction>,
action_page_open: SimpleAction, gobject: Box,
} }
impl Content { impl Content {
// Construct // Construct
/// Create new container for different components /// Create new container for different components
pub fn new(tab_action: Rc<TabAction>, action_page_open: SimpleAction) -> Self { pub fn new(window_action: Rc<WindowAction>, tab_action: Rc<TabAction>) -> Self {
Self { Self {
gobject: Box::builder().orientation(Orientation::Vertical).build(), gobject: Box::builder().orientation(Orientation::Vertical).build(),
window_action,
tab_action, tab_action,
action_page_open,
} }
} }
@ -88,8 +85,8 @@ impl Content {
let text = Text::gemini( let text = Text::gemini(
data, data,
base, base,
self.window_action.clone(),
self.tab_action.clone(), self.tab_action.clone(),
self.action_page_open.clone(),
); );
self.gobject.append(text.gobject()); self.gobject.append(text.gobject());
text text

View File

@ -2,9 +2,8 @@ mod gemini;
use gemini::Gemini; use gemini::Gemini;
use crate::app::browser::window::tab::action::Action as TabAction; use crate::app::browser::window::{tab::item::Action as TabAction, Action as WindowAction};
use gtk::{ use gtk::{
gio::SimpleAction,
glib::{GString, Uri}, glib::{GString, Uri},
ScrolledWindow, ScrolledWindow,
}; };
@ -24,11 +23,11 @@ impl Text {
pub fn gemini( pub fn gemini(
gemtext: &str, gemtext: &str,
base: &Uri, base: &Uri,
window_action: Rc<WindowAction>,
tab_action: Rc<TabAction>, tab_action: Rc<TabAction>,
action_page_open: SimpleAction,
) -> Self { ) -> Self {
// Init components // Init components
let gemini = Gemini::new(gemtext, base, tab_action, action_page_open); let gemini = Gemini::new(gemtext, base, window_action, tab_action);
// Init meta // Init meta
let meta = Meta { let meta = Meta {

View File

@ -4,12 +4,9 @@ mod widget;
use reader::Reader; use reader::Reader;
use widget::Widget; use widget::Widget;
use crate::app::browser::window::tab::action::Action as TabAction; use crate::app::browser::window::{tab::item::Action as TabAction, Action as WindowAction};
use adw::ClampScrollable; use adw::ClampScrollable;
use gtk::{ use gtk::glib::{GString, Uri};
gio::SimpleAction,
glib::{GString, Uri},
};
use std::rc::Rc; use std::rc::Rc;
pub struct Gemini { pub struct Gemini {
@ -22,11 +19,11 @@ impl Gemini {
pub fn new( pub fn new(
gemtext: &str, gemtext: &str,
base: &Uri, base: &Uri,
window_action: Rc<WindowAction>,
tab_action: Rc<TabAction>, tab_action: Rc<TabAction>,
action_page_open: SimpleAction,
) -> Self { ) -> Self {
// Init components // Init components
let reader = Rc::new(Reader::new(gemtext, base, tab_action, action_page_open)); let reader = Rc::new(Reader::new(gemtext, base, window_action, tab_action));
let widget = Rc::new(Widget::new(reader.gobject())); let widget = Rc::new(Widget::new(reader.gobject()));
// Result // Result

View File

@ -4,7 +4,7 @@ mod widget;
use tag::Tag; use tag::Tag;
use widget::Widget; use widget::Widget;
use crate::app::browser::window::tab::action::Action as TabAction; use crate::app::browser::window::{tab::item::Action as TabAction, Action as WindowAction};
use adw::StyleManager; use adw::StyleManager;
use gemtext::line::{ use gemtext::line::{
code::Code, code::Code,
@ -15,9 +15,9 @@ use gemtext::line::{
}; };
use gtk::{ use gtk::{
gdk::{BUTTON_MIDDLE, BUTTON_PRIMARY}, gdk::{BUTTON_MIDDLE, BUTTON_PRIMARY},
gio::{Cancellable, SimpleAction}, gio::Cancellable,
glib::{GString, TimeZone, Uri}, glib::{GString, TimeZone, Uri},
prelude::{ActionExt, TextBufferExt, TextBufferExtManual, TextViewExt, ToVariant, WidgetExt}, prelude::{TextBufferExt, TextBufferExtManual, TextViewExt, WidgetExt},
EventControllerMotion, GestureClick, TextBuffer, TextTag, TextView, TextWindowType, EventControllerMotion, GestureClick, TextBuffer, TextTag, TextView, TextWindowType,
UriLauncher, Window, WrapMode, UriLauncher, Window, WrapMode,
}; };
@ -33,8 +33,8 @@ impl Reader {
pub fn new( pub fn new(
gemtext: &str, gemtext: &str,
base: &Uri, base: &Uri,
window_action: Rc<WindowAction>,
tab_action: Rc<TabAction>, tab_action: Rc<TabAction>,
action_page_open: SimpleAction,
) -> Self { ) -> Self {
// Init default values // Init default values
let mut title = None; let mut title = None;
@ -232,7 +232,7 @@ impl Reader {
// Init events // Init events
primary_button_controller.connect_released({ primary_button_controller.connect_released({
let action_page_open = action_page_open.clone(); let tab_action = tab_action.clone();
let gobject = widget.gobject().clone(); let gobject = widget.gobject().clone();
let _links_ = links.clone(); // is copy let _links_ = links.clone(); // is copy
move |_, _, window_x, window_y| { move |_, _, window_x, window_y| {
@ -251,7 +251,7 @@ impl Reader {
return match uri.scheme().as_str() { return match uri.scheme().as_str() {
"gemini" => { "gemini" => {
// Open new page in browser // Open new page in browser
action_page_open.activate(Some(&uri.to_str().to_variant())); tab_action.load().activate(Some(&uri.to_str()));
} }
// Scheme not supported, delegate // Scheme not supported, delegate
_ => UriLauncher::new(&uri.to_str()).launch( _ => UriLauncher::new(&uri.to_str()).launch(
@ -259,8 +259,7 @@ impl Reader {
None::<&Cancellable>, None::<&Cancellable>,
|result| { |result| {
if let Err(error) = result { if let Err(error) = result {
// @TODO println!("{error}")
println!("Could not delegate launch action: {error}")
} }
}, },
), ),
@ -289,7 +288,7 @@ impl Reader {
return match uri.scheme().as_str() { return match uri.scheme().as_str() {
"gemini" => { "gemini" => {
// Open new page in browser // Open new page in browser
tab_action.open().activate(Some(&uri.to_string())); window_action.append().activate();
} }
// Scheme not supported, delegate // Scheme not supported, delegate
_ => UriLauncher::new(&uri.to_str()).launch( _ => UriLauncher::new(&uri.to_str()).launch(
@ -297,8 +296,7 @@ impl Reader {
None::<&Cancellable>, None::<&Cancellable>,
|result| { |result| {
if let Err(error) = result { if let Err(error) = result {
// @TODO println!("{error}")
println!("Could not delegate launch action: {error}")
} }
}, },
), ),

View File

@ -6,7 +6,7 @@ use response::Response;
use sensitive::Sensitive; use sensitive::Sensitive;
use widget::Widget; use widget::Widget;
use crate::app::browser::window::tab::action::Action as TabAction; use crate::app::browser::window::tab::item::Action as TabAction;
use adw::Clamp; use adw::Clamp;
use gtk::glib::Uri; use gtk::glib::Uri;
use std::rc::Rc; use std::rc::Rc;

View File

@ -8,7 +8,7 @@ use form::Form;
use title::Title; use title::Title;
use widget::Widget; use widget::Widget;
use crate::app::browser::window::tab::action::Action as TabAction; use crate::app::browser::window::tab::item::action::Action as TabAction;
use gtk::{ use gtk::{
gio::SimpleAction, gio::SimpleAction,
glib::{uuid_string_random, Uri, UriHideFlags}, glib::{uuid_string_random, Uri, UriHideFlags},
@ -63,7 +63,7 @@ impl Response {
action_send.connect_activate({ action_send.connect_activate({
let form = form.clone(); let form = form.clone();
move |_, _| { move |_, _| {
tab_action.open().activate(Some(&format!( tab_action.load().activate(Some(&format!(
"{}?{}", "{}?{}",
base.to_string_partial(UriHideFlags::QUERY), base.to_string_partial(UriHideFlags::QUERY),
Uri::escape_string(form.text().as_str(), None, false), Uri::escape_string(form.text().as_str(), None, false),

View File

@ -4,7 +4,7 @@ mod widget;
use form::Form; use form::Form;
use widget::Widget; use widget::Widget;
use crate::app::browser::window::tab::action::Action as TabAction; use crate::app::browser::window::tab::item::action::Action as TabAction;
use gtk::{ use gtk::{
gio::SimpleAction, gio::SimpleAction,
glib::{uuid_string_random, Uri, UriHideFlags}, glib::{uuid_string_random, Uri, UriHideFlags},
@ -44,7 +44,7 @@ impl Sensitive {
action_send.connect_activate({ action_send.connect_activate({
let form = form.clone(); let form = form.clone();
move |_, _| { move |_, _| {
tab_action.open().activate(Some(&format!( tab_action.load().activate(Some(&format!(
"{}?{}", "{}?{}",
base.to_string_partial(UriHideFlags::QUERY), base.to_string_partial(UriHideFlags::QUERY),
Uri::escape_string(form.text().as_str(), None, false), Uri::escape_string(form.text().as_str(), None, false),

View File

@ -14,9 +14,10 @@ use reload::Reload;
use request::Request; use request::Request;
use widget::Widget; use widget::Widget;
use crate::app::browser::action::Action as BrowserAction; use crate::app::browser::window::tab::item::Action as TabAction;
use crate::app::browser::window::action::Action as WindowAction; use crate::app::browser::window::Action as WindowAction;
use gtk::{gio::SimpleAction, prelude::EditableExt}; use crate::app::browser::Action as BrowserAction;
use gtk::prelude::EditableExt;
use sqlite::Transaction; use sqlite::Transaction;
use std::rc::Rc; use std::rc::Rc;
@ -33,22 +34,22 @@ impl Navigation {
pub fn new( pub fn new(
browser_action: Rc<BrowserAction>, browser_action: Rc<BrowserAction>,
window_action: Rc<WindowAction>, window_action: Rc<WindowAction>,
action_page_open: SimpleAction, tab_action: Rc<TabAction>,
) -> Self { ) -> Self {
// Init components // Init components
let home = Rc::new(Home::new(window_action.clone())); let home = Rc::new(Home::new(window_action.clone()));
let history = Rc::new(History::new(window_action.clone())); let history = Rc::new(History::new(window_action.clone()));
let reload = Rc::new(Reload::new(window_action)); let reload = Rc::new(Reload::new(window_action));
let request = Rc::new(Request::new(browser_action, action_page_open.clone())); let request = Rc::new(Request::new(browser_action, tab_action));
let bookmark = Rc::new(Bookmark::new()); let bookmark = Rc::new(Bookmark::new());
// Init widget // Init widget
let widget = Rc::new(Widget::new( let widget = Rc::new(Widget::new(
home.gobject(), home.widget().gobject(),
history.gobject(), history.widget().gobject(),
reload.gobject(), reload.widget().gobject(),
request.widget().gobject(), request.widget().gobject(),
bookmark.gobject(), bookmark.widget().gobject(),
)); ));
// Done // Done

View File

@ -2,7 +2,6 @@ mod widget;
use widget::Widget; use widget::Widget;
use gtk::Button;
use std::rc::Rc; use std::rc::Rc;
pub struct Bookmark { pub struct Bookmark {
@ -23,7 +22,8 @@ impl Bookmark {
} }
// Getters // Getters
pub fn gobject(&self) -> &Button {
self.widget.gobject() pub fn widget(&self) -> &Rc<Widget> {
&self.widget
} }
} }

View File

@ -7,7 +7,7 @@ use forward::Forward;
use widget::Widget; use widget::Widget;
use crate::app::browser::window::action::Action as WindowAction; use crate::app::browser::window::action::Action as WindowAction;
use gtk::{glib::GString, Box}; use gtk::glib::GString;
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
struct Memory { struct Memory {
@ -34,7 +34,10 @@ impl History {
let forward = Rc::new(Forward::new(window_action)); let forward = Rc::new(Forward::new(window_action));
// Init widget // Init widget
let widget = Rc::new(Widget::new(back.gobject(), forward.gobject())); let widget = Rc::new(Widget::new(
back.widget().gobject(),
forward.widget().gobject(),
));
// Init memory // Init memory
let memory = RefCell::new(Vec::new()); let memory = RefCell::new(Vec::new());
@ -122,7 +125,8 @@ impl History {
} }
// Getters // Getters
pub fn gobject(&self) -> &Box {
self.widget.gobject() pub fn widget(&self) -> &Rc<Widget> {
&self.widget
} }
} }

View File

@ -3,7 +3,6 @@ mod widget;
use widget::Widget; use widget::Widget;
use crate::app::browser::window::action::Action as WindowAction; use crate::app::browser::window::action::Action as WindowAction;
use gtk::Button;
use std::rc::Rc; use std::rc::Rc;
pub struct Back { pub struct Back {
@ -12,7 +11,8 @@ pub struct Back {
} }
impl Back { impl Back {
// Construct // Constructors
pub fn new(window_action: Rc<WindowAction>) -> Self { pub fn new(window_action: Rc<WindowAction>) -> Self {
Self { Self {
window_action: window_action.clone(), window_action: window_action.clone(),
@ -21,6 +21,7 @@ impl Back {
} }
// Actions // Actions
pub fn update(&self, status: bool) { pub fn update(&self, status: bool) {
// Update actions // Update actions
self.window_action self.window_action
@ -33,7 +34,8 @@ impl Back {
} }
// Getters // Getters
pub fn gobject(&self) -> &Button {
self.widget.gobject() pub fn widget(&self) -> &Rc<Widget> {
&self.widget
} }
} }

View File

@ -3,7 +3,6 @@ mod widget;
use widget::Widget; use widget::Widget;
use crate::app::browser::window::action::Action as WindowAction; use crate::app::browser::window::action::Action as WindowAction;
use gtk::Button;
use std::rc::Rc; use std::rc::Rc;
pub struct Forward { pub struct Forward {
@ -33,7 +32,8 @@ impl Forward {
} }
// Getters // Getters
pub fn gobject(&self) -> &Button {
self.widget.gobject() pub fn widget(&self) -> &Rc<Widget> {
&self.widget
} }
} }

View File

@ -3,10 +3,7 @@ mod widget;
use widget::Widget; use widget::Widget;
use crate::app::browser::window::action::Action as WindowAction; use crate::app::browser::window::action::Action as WindowAction;
use gtk::{ use gtk::glib::{gformat, GString, Uri};
glib::{gformat, GString, Uri},
Button,
};
use std::{cell::RefCell, rc::Rc}; use std::{cell::RefCell, rc::Rc};
pub struct Home { pub struct Home {
@ -44,8 +41,8 @@ impl Home {
} }
// Getters // Getters
pub fn gobject(&self) -> &Button { pub fn widget(&self) -> &Rc<Widget> {
self.widget.gobject() &self.widget
} }
pub fn url(&self) -> Option<GString> { pub fn url(&self) -> Option<GString> {

View File

@ -3,7 +3,6 @@ mod widget;
use widget::Widget; use widget::Widget;
use crate::app::browser::window::action::Action as WindowAction; use crate::app::browser::window::action::Action as WindowAction;
use gtk::Button;
use std::rc::Rc; use std::rc::Rc;
pub struct Reload { pub struct Reload {
@ -21,6 +20,7 @@ impl Reload {
} }
// Actions // Actions
pub fn update(&self, is_enabled: bool) { pub fn update(&self, is_enabled: bool) {
// Update actions // Update actions
self.window_action self.window_action
@ -33,7 +33,8 @@ impl Reload {
} }
// Getters // Getters
pub fn gobject(&self) -> &Button {
self.widget.gobject() pub fn widget(&self) -> &Rc<Widget> {
&self.widget
} }
} }

View File

@ -4,9 +4,8 @@ mod widget;
use database::Database; use database::Database;
use widget::Widget; use widget::Widget;
use crate::app::browser::action::Action as BrowserAction; use crate::app::browser::{window::tab::item::Action as TabAction, Action as BrowserAction};
use gtk::{ use gtk::{
gio::SimpleAction,
glib::{Uri, UriFlags}, glib::{Uri, UriFlags},
prelude::EditableExt, prelude::EditableExt,
}; };
@ -23,10 +22,10 @@ impl Request {
pub fn new( pub fn new(
// Actions // Actions
browser_action: Rc<BrowserAction>, browser_action: Rc<BrowserAction>,
action_page_reload: SimpleAction, // @TODO local `action_page_open`? tab_action: Rc<TabAction>,
) -> Self { ) -> Self {
Self { Self {
widget: Rc::new(Widget::new(browser_action, action_page_reload)), widget: Rc::new(Widget::new(browser_action, tab_action)),
} }
} }

View File

@ -2,11 +2,10 @@ mod database;
use database::Database; use database::Database;
use crate::app::browser::action::Action as BrowserAction; use crate::app::browser::{window::tab::item::Action as TabAction, Action as BrowserAction};
use gtk::{ use gtk::{
gio::SimpleAction,
glib::{timeout_add_local, ControlFlow, SourceId}, glib::{timeout_add_local, ControlFlow, SourceId},
prelude::{ActionExt, EditableExt, EntryExt, ToVariant, WidgetExt}, prelude::{EditableExt, EntryExt, WidgetExt},
Entry, StateFlags, Entry, StateFlags,
}; };
use sqlite::Transaction; use sqlite::Transaction;
@ -30,7 +29,7 @@ pub struct Widget {
impl Widget { impl Widget {
// Construct // Construct
pub fn new(browser_action: Rc<BrowserAction>, action_page_open: SimpleAction) -> Self { pub fn new(browser_action: Rc<BrowserAction>, tab_action: Rc<TabAction>) -> Self {
// Init animated progress bar state // Init animated progress bar state
let progress = Rc::new(Progress { let progress = Rc::new(Progress {
fraction: RefCell::new(0.0), fraction: RefCell::new(0.0),
@ -49,7 +48,7 @@ impl Widget {
}); });
gobject.connect_activate(move |this| { gobject.connect_activate(move |this| {
action_page_open.activate(Some(&this.text().to_variant())); tab_action.load().activate(Some(&this.text()));
}); });
gobject.connect_state_flags_changed({ gobject.connect_state_flags_changed({

View File

@ -1,7 +1,5 @@
use gtk::{ use gtk::{
gio::{SimpleAction, SimpleActionGroup}, prelude::{BoxExt, IsA},
glib::uuid_string_random,
prelude::{ActionMapExt, BoxExt, IsA, WidgetExt},
Box, Orientation, Box, Orientation,
}; };
@ -13,17 +11,11 @@ impl Widget {
// Construct // Construct
pub fn new( pub fn new(
name: &str, name: &str,
// Actions
action_page_open: SimpleAction,
// Components // Components
navigation: &impl IsA<gtk::Widget>, navigation: &impl IsA<gtk::Widget>,
content: &impl IsA<gtk::Widget>, content: &impl IsA<gtk::Widget>,
input: &impl IsA<gtk::Widget>, input: &impl IsA<gtk::Widget>,
) -> Self { ) -> Self {
// Init additional action group
let action_group = SimpleActionGroup::new();
action_group.add_action(&action_page_open);
// Init self // Init self
let gobject = Box::builder() let gobject = Box::builder()
.orientation(Orientation::Vertical) .orientation(Orientation::Vertical)
@ -34,8 +26,6 @@ impl Widget {
gobject.append(content); gobject.append(content);
gobject.append(input); gobject.append(input);
gobject.insert_action_group(&uuid_string_random(), Some(&action_group));
Self { gobject } Self { gobject }
} }