diff --git a/src/app/browser/window/tab/item/page/input.rs b/src/app/browser/window/tab/item/page/input.rs index 18be5baa..1afe40cd 100644 --- a/src/app/browser/window/tab/item/page/input.rs +++ b/src/app/browser/window/tab/item/page/input.rs @@ -4,7 +4,11 @@ mod titan; use super::ItemAction; use adw::Clamp; -use gtk::{glib::Uri, prelude::WidgetExt}; +use gtk::{ + glib::Uri, + prelude::{IsA, WidgetExt}, + Widget, +}; use response::Response; use sensitive::Sensitive; use std::rc::Rc; @@ -37,10 +41,10 @@ impl Input { // Actions pub fn unset(&self) { - self.update(None); + self.update(Widget::NONE); } - pub fn update(&self, child: Option<>k::Box>) { + pub fn update(&self, child: Option<&impl IsA>) { if child.is_some() { self.clamp.set_visible(true); // widget may be hidden, make it visible to child redraw self.clamp.set_child(child); @@ -71,6 +75,6 @@ impl Input { } pub fn set_new_titan(&self, on_send: impl Fn(&[u8], Box) + 'static) { - self.update(Some(>k::Box::titan(on_send))); + self.update(Some(>k::Notebook::titan(on_send))); } } diff --git a/src/app/browser/window/tab/item/page/input/titan.rs b/src/app/browser/window/tab/item/page/input/titan.rs index 87d857be..7f120cb2 100644 --- a/src/app/browser/window/tab/item/page/input/titan.rs +++ b/src/app/browser/window/tab/item/page/input/titan.rs @@ -1,67 +1,55 @@ -mod control; -mod form; +mod file; +mod text; mod title; -use control::Control; -use control::Send; -use form::Form; -use gtk::{ - prelude::{BoxExt, ButtonExt, TextBufferExt, TextViewExt}, - Label, Orientation, TextView, -}; -use std::rc::Rc; +use file::File; +use gtk::{glib::uuid_string_random, prelude::WidgetExt, Label, Notebook}; +use text::Text; use title::Title; -const MARGIN: i32 = 6; -const SPACING: i32 = 8; - pub trait Titan { fn titan(callback: impl Fn(&[u8], Box) + 'static) -> Self; } -impl Titan for gtk::Box { +impl Titan for Notebook { fn titan(callback: impl Fn(&[u8], Box) + 'static) -> Self { - // Init components - let control = Rc::new(Control::build()); - let form = TextView::form(); - let title = Label::title(None); - - // Init widget - let g_box = gtk::Box::builder() - .margin_bottom(MARGIN) - .margin_end(MARGIN) - .margin_start(MARGIN) - .margin_top(MARGIN) - .spacing(SPACING) - .orientation(Orientation::Vertical) + let notebook = Notebook::builder() + .name(format!("s{}", uuid_string_random())) + .show_border(false) .build(); - g_box.append(&title); - g_box.append(&form); - g_box.append(&control.g_box); + notebook.append_page(>k::Box::text(callback), Some(&Label::title("Text"))); + notebook.append_page(>k::Box::file(), Some(&Label::title("File"))); - // Connect events - control.send.connect_clicked({ - let form = form.clone(); - move |this| { - this.set_sending(); - callback( - form.text().as_bytes(), - Box::new({ - let this = this.clone(); - move || this.set_resend() // on failure - }), - ) - } - }); - - form.buffer().connect_changed({ - let control = control.clone(); - let form = form.clone(); - move |this| control.update(this.char_count(), form.text().len()) - }); - - // Return activated `Self` - g_box + notebook_css_patch(¬ebook); + notebook } } + +// Tools + +fn notebook_css_patch(notebook: &Notebook) { + let name = notebook.widget_name(); + let provider = gtk::CssProvider::new(); + + provider.load_from_string(&format!( + " + #{name} stack {{ + background-color:rgba(0,0,0,0); + }} + #{name} header {{ + border-bottom-color:rgba(0,0,0,0); + }} + #{name} tab {{ + opacity:0.9; + }} + " + )); + + gtk::style_context_add_provider_for_display( + ¬ebook.display(), + &provider, + gtk::STYLE_PROVIDER_PRIORITY_APPLICATION, + ); +} // @TODO replace `Notebook` with `ToggleGroup` in Adw 1.7 / Ubuntu 26.04 + // https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.ToggleGroup.html diff --git a/src/app/browser/window/tab/item/page/input/titan/control/send.rs b/src/app/browser/window/tab/item/page/input/titan/control/send.rs deleted file mode 100644 index e465330d..00000000 --- a/src/app/browser/window/tab/item/page/input/titan/control/send.rs +++ /dev/null @@ -1,28 +0,0 @@ -use gtk::{ - prelude::{ButtonExt, WidgetExt}, - Button, -}; - -pub trait Send { - fn send() -> Self; - fn set_sending(&self); - fn set_resend(&self); -} - -impl Send for Button { - fn send() -> Self { - Button::builder() - .css_classes(["accent"]) // | `suggested-action` - .label("Send") - .sensitive(false) - .build() - } - fn set_sending(&self) { - self.set_sensitive(false); - self.set_label("sending.."); - } - fn set_resend(&self) { - self.set_sensitive(true); - self.set_label("Resend"); - } -} diff --git a/src/app/browser/window/tab/item/page/input/titan/file.rs b/src/app/browser/window/tab/item/page/input/titan/file.rs new file mode 100644 index 00000000..c2075751 --- /dev/null +++ b/src/app/browser/window/tab/item/page/input/titan/file.rs @@ -0,0 +1,31 @@ +use gtk::{prelude::BoxExt, Align, Label, Orientation}; + +const MARGIN: i32 = 8; +const SPACING: i32 = 8; + +pub trait File { + fn file() -> Self; +} + +impl File for gtk::Box { + fn file() -> Self { + // Init widget + let g_box = gtk::Box::builder() + .halign(Align::Center) + .margin_bottom(MARGIN) + .margin_end(MARGIN) + .margin_start(MARGIN) + .orientation(Orientation::Vertical) + .spacing(SPACING) + //.margin_top(MARGIN) + .build(); + + g_box.append( + &Label::builder() + .css_classes(["dim-label"]) + .label("Soon..") + .build(), + ); // @TODO + g_box + } +} diff --git a/src/app/browser/window/tab/item/page/input/titan/text.rs b/src/app/browser/window/tab/item/page/input/titan/text.rs new file mode 100644 index 00000000..2ca41029 --- /dev/null +++ b/src/app/browser/window/tab/item/page/input/titan/text.rs @@ -0,0 +1,62 @@ +mod control; +mod form; + +use control::Control; +use control::Upload; +use form::Form; +use gtk::{ + prelude::{BoxExt, ButtonExt, TextBufferExt, TextViewExt}, + Orientation, TextView, +}; +use std::rc::Rc; + +const MARGIN: i32 = 8; +const SPACING: i32 = 8; + +pub trait Text { + fn text(callback: impl Fn(&[u8], Box) + 'static) -> Self; +} + +impl Text for gtk::Box { + fn text(callback: impl Fn(&[u8], Box) + 'static) -> Self { + // Init components + let control = Rc::new(Control::build()); + let form = TextView::form(); + + // Init widget + let g_box = gtk::Box::builder() + .margin_bottom(MARGIN) + .margin_end(MARGIN) + .margin_start(MARGIN) + .orientation(Orientation::Vertical) + .spacing(SPACING) + //.margin_top(MARGIN) + .build(); + + g_box.append(&form); + g_box.append(&control.g_box); + + // Connect events + control.upload.connect_clicked({ + let form = form.clone(); + move |this| { + this.set_uploading(); + callback( + form.text().as_bytes(), + Box::new({ + let this = this.clone(); + move || this.set_resend() // on failure + }), + ) + } + }); + + form.buffer().connect_changed({ + let control = control.clone(); + let form = form.clone(); + move |this| control.update(this.char_count(), form.text().len()) + }); + + g_box + } +} diff --git a/src/app/browser/window/tab/item/page/input/titan/control.rs b/src/app/browser/window/tab/item/page/input/titan/text/control.rs similarity index 81% rename from src/app/browser/window/tab/item/page/input/titan/control.rs rename to src/app/browser/window/tab/item/page/input/titan/text/control.rs index 98f88276..91f2347c 100644 --- a/src/app/browser/window/tab/item/page/input/titan/control.rs +++ b/src/app/browser/window/tab/item/page/input/titan/text/control.rs @@ -1,18 +1,18 @@ mod counter; -mod send; +mod upload; use counter::Counter; use gtk::{ prelude::{BoxExt, WidgetExt}, Align, Box, Button, Label, Orientation, }; -pub use send::Send; +pub use upload::Upload; const SPACING: i32 = 8; pub struct Control { pub counter: Label, - pub send: Button, + pub upload: Button, pub g_box: Box, } @@ -23,7 +23,7 @@ impl Control { pub fn build() -> Self { // Init components let counter = Label::counter(); - let send = Button::send(); + let upload = Button::upload(); // Init main widget let g_box = Box::builder() @@ -33,12 +33,12 @@ impl Control { .build(); g_box.append(&counter); - g_box.append(&send); + g_box.append(&upload); // Return activated struct Self { counter, - send, + upload, g_box, } } @@ -47,6 +47,6 @@ impl Control { pub fn update(&self, chars_count: i32, bytes_total: usize) { // Update children components self.counter.update(chars_count, bytes_total); - self.send.set_sensitive(bytes_total > 0); + self.upload.set_sensitive(bytes_total > 0); } } diff --git a/src/app/browser/window/tab/item/page/input/titan/control/counter.rs b/src/app/browser/window/tab/item/page/input/titan/text/control/counter.rs similarity index 100% rename from src/app/browser/window/tab/item/page/input/titan/control/counter.rs rename to src/app/browser/window/tab/item/page/input/titan/text/control/counter.rs diff --git a/src/app/browser/window/tab/item/page/input/titan/text/control/upload.rs b/src/app/browser/window/tab/item/page/input/titan/text/control/upload.rs new file mode 100644 index 00000000..c6099c5a --- /dev/null +++ b/src/app/browser/window/tab/item/page/input/titan/text/control/upload.rs @@ -0,0 +1,30 @@ +use gtk::{ + prelude::{ButtonExt, WidgetExt}, + Button, +}; + +pub trait Upload { + fn upload() -> Self; + fn set_uploading(&self); + fn set_resend(&self); +} + +impl Upload for Button { + fn upload() -> Self { + Button::builder() + // @TODO this class not looks well with default GTK Notebook widget + // activate it after upgrade to `ToggleGroup` in Adw v1.7 / Ubuntu 26.04 + // .css_classes(["accent"]) // | `suggested-action` + .label("Upload") + .sensitive(false) + .build() + } + fn set_uploading(&self) { + self.set_sensitive(false); + self.set_label("uploading.."); + } + fn set_resend(&self) { + self.set_sensitive(true); + self.set_label("Resend"); + } +} diff --git a/src/app/browser/window/tab/item/page/input/titan/form.rs b/src/app/browser/window/tab/item/page/input/titan/text/form.rs similarity index 97% rename from src/app/browser/window/tab/item/page/input/titan/form.rs rename to src/app/browser/window/tab/item/page/input/titan/text/form.rs index 0ab7cd9d..479049d6 100644 --- a/src/app/browser/window/tab/item/page/input/titan/form.rs +++ b/src/app/browser/window/tab/item/page/input/titan/text/form.rs @@ -33,7 +33,7 @@ impl Form for TextView { .css_classes(["frame", "view"]) .extra_menu(&adapter.menu_model()) .left_margin(MARGIN) - .margin_bottom(MARGIN / 4) + .margin_bottom(MARGIN / 2) .right_margin(MARGIN) .top_margin(MARGIN) .wrap_mode(WrapMode::Word) diff --git a/src/app/browser/window/tab/item/page/input/titan/title.rs b/src/app/browser/window/tab/item/page/input/titan/title.rs index 535c73c6..6faef878 100644 --- a/src/app/browser/window/tab/item/page/input/titan/title.rs +++ b/src/app/browser/window/tab/item/page/input/titan/title.rs @@ -1,15 +1,14 @@ -use gtk::{Align, Label}; +use gtk::Label; pub trait Title { - fn title(title: Option<&str>) -> Self; + fn title(label: &str) -> Self; } impl Title for Label { - fn title(title: Option<&str>) -> Self { + fn title(label: &str) -> Self { Label::builder() .css_classes(["heading"]) - .halign(Align::Start) - .label(title.unwrap_or("Titan input")) + .label(label) .build() } }