mirror of
https://github.com/YGGverse/Yoda.git
synced 2025-01-15 09:10:08 +00:00
implement new tab position enum
This commit is contained in:
parent
57cdc4cee9
commit
23e4e83e45
@ -23,6 +23,8 @@ use gtk::{
|
||||
};
|
||||
use std::rc::Rc;
|
||||
|
||||
pub use append::Position; // public enum
|
||||
|
||||
/// [SimpleActionGroup](https://docs.gtk.org/gio/class.SimpleActionGroup.html) wrapper for `Browser` actions
|
||||
pub struct Action {
|
||||
// Actions
|
||||
|
@ -1,11 +1,34 @@
|
||||
use gtk::{
|
||||
gio::SimpleAction,
|
||||
glib::{uuid_string_random, GString},
|
||||
glib::{uuid_string_random, GString, Variant},
|
||||
prelude::{ActionExt, ToVariant},
|
||||
};
|
||||
|
||||
/// C-compatible variant type defaults
|
||||
const DEFAULT_POSITION: i32 = -1;
|
||||
/// Append options
|
||||
pub enum Position {
|
||||
After,
|
||||
End,
|
||||
Number(i32),
|
||||
}
|
||||
|
||||
// C-compatible Position values
|
||||
const POSITION_AFTER: i32 = -1;
|
||||
const POSITION_END: i32 = -2;
|
||||
|
||||
// Implement conversion trait
|
||||
impl ToVariant for Position {
|
||||
fn to_variant(&self) -> Variant {
|
||||
match self {
|
||||
Position::After => &POSITION_AFTER,
|
||||
Position::End => &POSITION_END,
|
||||
Position::Number(value) => value,
|
||||
}
|
||||
.to_variant()
|
||||
}
|
||||
}
|
||||
|
||||
// Action state defaults
|
||||
const DEFAULT_POSITION: Position = Position::End;
|
||||
const DEFAULT_REQUEST: String = String::new();
|
||||
const DEFAULT_IS_PINNED: bool = false;
|
||||
const DEFAULT_IS_SELECTED: bool = true;
|
||||
@ -50,7 +73,7 @@ impl Append {
|
||||
|
||||
// Set default state
|
||||
self.change_state(
|
||||
Some(DEFAULT_POSITION),
|
||||
DEFAULT_POSITION,
|
||||
Some(DEFAULT_REQUEST),
|
||||
DEFAULT_IS_PINNED,
|
||||
DEFAULT_IS_SELECTED,
|
||||
@ -76,7 +99,7 @@ impl Append {
|
||||
/// * this action reset previous state for action after activation
|
||||
pub fn activate_stateful_once(
|
||||
&self,
|
||||
position: Option<i32>,
|
||||
position: Position,
|
||||
request: Option<String>,
|
||||
is_pinned: bool,
|
||||
is_selected: bool,
|
||||
@ -114,7 +137,7 @@ impl Append {
|
||||
/// Emit state change for action
|
||||
pub fn change_state(
|
||||
&self,
|
||||
position: Option<i32>,
|
||||
position: Position,
|
||||
request: Option<String>,
|
||||
is_pinned: bool,
|
||||
is_selected: bool,
|
||||
@ -124,11 +147,7 @@ impl Append {
|
||||
self.gobject.change_state(
|
||||
&(
|
||||
// Convert Option to C-based variant value
|
||||
if let Some(position) = position {
|
||||
position
|
||||
} else {
|
||||
DEFAULT_POSITION
|
||||
},
|
||||
position,
|
||||
if let Some(request) = request {
|
||||
request
|
||||
} else {
|
||||
@ -150,7 +169,7 @@ impl Append {
|
||||
/// * return `position`,`request`,`is_pinned`,`is_selected`,`is_attention`,`is_load` state as tuple
|
||||
pub fn connect_activate(
|
||||
&self,
|
||||
callback: impl Fn(Option<i32>, Option<String>, bool, bool, bool, bool) + 'static,
|
||||
callback: impl Fn(Position, Option<String>, bool, bool, bool, bool) + 'static,
|
||||
) {
|
||||
self.gobject.connect_activate(move |this, _| {
|
||||
let (position, request, is_pinned, is_selected, is_attention, is_load) = state(this);
|
||||
@ -179,18 +198,18 @@ impl Append {
|
||||
}
|
||||
|
||||
/// Shared helper to get C-based action state in Optional format
|
||||
pub fn state(this: &SimpleAction) -> (Option<i32>, Option<String>, bool, bool, bool, bool) {
|
||||
pub fn state(this: &SimpleAction) -> (Position, Option<String>, bool, bool, bool, bool) {
|
||||
let (position, request, is_pinned, is_selected, is_attention, is_load) = this
|
||||
.state()
|
||||
.expect("Expected (`position`,`request`,`is_pinned`,`is_selected`,`is_attention`,`is_load`) state")
|
||||
.get::<(i32, String, bool, bool, bool, bool)>()
|
||||
.expect("Parameter type does not match (`i32`,`String`,`bool`,`bool`,`bool`,`bool`) tuple");
|
||||
(
|
||||
// Convert from C-based variant value to Option
|
||||
if position == DEFAULT_POSITION {
|
||||
None
|
||||
} else {
|
||||
Some(position)
|
||||
// Convert from C-based variant value to Position enum
|
||||
match position {
|
||||
POSITION_AFTER => Position::After,
|
||||
POSITION_END => Position::End,
|
||||
value => Position::Number(value),
|
||||
},
|
||||
if request.is_empty() {
|
||||
None
|
||||
|
@ -8,8 +8,10 @@ use item::Item;
|
||||
use menu::Menu;
|
||||
use widget::Widget;
|
||||
|
||||
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, Position},
|
||||
Action as BrowserAction,
|
||||
};
|
||||
use gtk::{
|
||||
glib::{GString, Propagation},
|
||||
prelude::WidgetExt,
|
||||
@ -103,7 +105,7 @@ impl Tab {
|
||||
// Actions
|
||||
pub fn append(
|
||||
&self,
|
||||
position: Option<i32>,
|
||||
position: Position,
|
||||
request: Option<String>,
|
||||
is_pinned: bool,
|
||||
is_selected: bool,
|
||||
@ -321,7 +323,7 @@ impl Tab {
|
||||
pub fn init(&self) {
|
||||
// Append just one blank page if no tabs available after last session restore
|
||||
if self.index.borrow().is_empty() {
|
||||
self.append(None, None, false, true, false, false);
|
||||
self.append(Position::End, None, false, true, false, false);
|
||||
}
|
||||
|
||||
// @TODO other/child features..
|
||||
|
@ -8,7 +8,10 @@ use database::Database;
|
||||
use page::Page;
|
||||
use widget::Widget;
|
||||
|
||||
use crate::app::browser::{window::Action as WindowAction, Action as BrowserAction};
|
||||
use crate::app::browser::{
|
||||
window::action::{Action as WindowAction, Position},
|
||||
Action as BrowserAction,
|
||||
};
|
||||
use adw::TabView;
|
||||
use gtk::{
|
||||
glib::{uuid_string_random, GString},
|
||||
@ -34,7 +37,7 @@ impl Item {
|
||||
browser_action: Rc<BrowserAction>,
|
||||
window_action: Rc<WindowAction>,
|
||||
// Options tuple @TODO struct?
|
||||
options: (Option<i32>, Option<String>, bool, bool, bool, bool),
|
||||
options: (Position, Option<String>, bool, bool, bool, bool),
|
||||
) -> Self {
|
||||
// Get item options from tuple
|
||||
let (position, request, is_pinned, is_selected, is_attention, is_load) = options;
|
||||
@ -150,7 +153,7 @@ impl Item {
|
||||
window_action.clone(),
|
||||
// Options tuple
|
||||
(
|
||||
None,
|
||||
Position::End,
|
||||
None,
|
||||
record.is_pinned,
|
||||
record.is_selected,
|
||||
|
@ -4,7 +4,9 @@ mod widget;
|
||||
use tag::Tag;
|
||||
use widget::Widget;
|
||||
|
||||
use crate::app::browser::window::{tab::item::Action as TabAction, Action as WindowAction};
|
||||
use crate::app::browser::window::{
|
||||
action::Position, tab::item::Action as TabAction, Action as WindowAction,
|
||||
};
|
||||
use adw::StyleManager;
|
||||
use gemtext::line::{
|
||||
code::Code,
|
||||
@ -283,7 +285,7 @@ impl Reader {
|
||||
"gemini" => {
|
||||
// Open new page in browser
|
||||
actions.0.append().activate_stateful_once(
|
||||
None,
|
||||
Position::After,
|
||||
Some(uri.to_string()),
|
||||
false,
|
||||
false,
|
||||
|
@ -2,6 +2,7 @@ mod database;
|
||||
|
||||
use database::Database;
|
||||
|
||||
use crate::app::browser::window::action::Position;
|
||||
use adw::{TabPage, TabView};
|
||||
use gtk::prelude::IsA;
|
||||
use sqlite::Transaction;
|
||||
@ -13,34 +14,32 @@ pub struct Widget {
|
||||
}
|
||||
|
||||
impl Widget {
|
||||
// Construct
|
||||
// Constructors
|
||||
|
||||
pub fn new(
|
||||
keyword: &str, // ID
|
||||
tab_view: &TabView,
|
||||
child: &impl IsA<gtk::Widget>,
|
||||
title: Option<&str>,
|
||||
position: Option<i32>,
|
||||
position: Position,
|
||||
state: (bool, bool, bool),
|
||||
) -> Self {
|
||||
let gobject = match position {
|
||||
Some(value) => {
|
||||
// If given `position` match pinned tab, GTK will panic with notice:
|
||||
// adw_tab_view_insert: assertion 'position >= self->n_pinned_pages'
|
||||
// as the solution, prepend new page after pinned tabs on this case
|
||||
if value > tab_view.n_pinned_pages() {
|
||||
tab_view.insert(child, value)
|
||||
} else {
|
||||
tab_view.prepend(child)
|
||||
}
|
||||
}
|
||||
None => tab_view.append(child),
|
||||
};
|
||||
|
||||
// Define state variables
|
||||
let (is_pinned, is_selected, is_attention) = state;
|
||||
|
||||
// Create new `TabPage` GObject in given `TabView`
|
||||
let gobject = match position {
|
||||
Position::After => match tab_view.selected_page() {
|
||||
Some(page) => add(tab_view, child, tab_view.page_position(&page) + 1),
|
||||
None => tab_view.append(child),
|
||||
},
|
||||
Position::End => tab_view.append(child),
|
||||
Position::Number(value) => add(tab_view, child, value),
|
||||
};
|
||||
|
||||
// Setup `GObject`
|
||||
gobject.set_needs_attention(is_attention);
|
||||
gobject.set_keyword(keyword);
|
||||
|
||||
gobject.set_title(match title {
|
||||
Some(value) => value,
|
||||
None => DEFAULT_TITLE,
|
||||
@ -52,10 +51,12 @@ impl Widget {
|
||||
tab_view.set_selected_page(&gobject);
|
||||
}
|
||||
|
||||
// Done
|
||||
Self { gobject }
|
||||
}
|
||||
|
||||
// Actions
|
||||
|
||||
pub fn clean(
|
||||
&self,
|
||||
transaction: &Transaction,
|
||||
@ -131,12 +132,14 @@ impl Widget {
|
||||
}
|
||||
|
||||
// Getters
|
||||
|
||||
pub fn gobject(&self) -> &TabPage {
|
||||
&self.gobject
|
||||
}
|
||||
}
|
||||
|
||||
// Tools
|
||||
|
||||
pub fn migrate(tx: &Transaction) -> Result<(), String> {
|
||||
// Migrate self components
|
||||
if let Err(e) = Database::init(tx) {
|
||||
@ -149,3 +152,17 @@ pub fn migrate(tx: &Transaction) -> Result<(), String> {
|
||||
// Success
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Create new [TabPage](https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.TabPage.html)
|
||||
/// in [TabView](https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.TabView.html) at given position
|
||||
///
|
||||
/// * if given `position` match pinned tab, GTK will panic with notice:
|
||||
/// adw_tab_view_insert: assertion 'position >= self->n_pinned_pages'\
|
||||
/// as the solution, prepend new page after pinned tabs in this case
|
||||
fn add(tab_view: &TabView, child: &impl IsA<gtk::Widget>, position: i32) -> TabPage {
|
||||
if position > tab_view.n_pinned_pages() {
|
||||
tab_view.insert(child, position)
|
||||
} else {
|
||||
tab_view.prepend(child)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user