mod control;
mod file;
mod header;
mod tab;
mod text;
use control::Control;
use file::File;
use gtk::{
Notebook,
glib::Bytes,
prelude::{DisplayExt, WidgetExt},
};
pub use header::Header;
use tab::Tab;
use text::Text;
pub trait Titan {
fn titan(
max_content_height: i32,
callback: impl Fn(Header, Bytes, Box<dyn Fn()>) + 'static,
) -> Self;
}
impl Titan for gtk::Box {
fn titan(
max_content_height: i32,
callback: impl Fn(Header, Bytes, Box<dyn Fn()>) + 'static,
) -> Self {
use gtk::{Label, glib::uuid_string_random, prelude::ButtonExt};
use std::rc::Rc;
let control = Rc::new(Control::build());
let file = Rc::new(File::build(&control));
let text = Rc::new(Text::build(&control));
let notebook = {
let notebook = Notebook::builder()
.name(format!("s{}", uuid_string_random()))
.show_border(false)
.build();
notebook.append_page(
>k::ScrolledWindow::builder()
.child(&text.text_view)
.max_content_height(max_content_height)
.propagate_natural_height(true)
.build(),
Some(&Label::tab("Text")),
);
notebook.append_page(&file.button, Some(&Label::tab("File")));
notebook.connect_switch_page({
let control = control.clone();
let file = file.clone();
let text = text.clone();
move |_, _, tab_number| {
if tab_number == 0 {
control.update(Some(text.len()), Some(text.count()))
} else {
control.update(file.size(), None)
}
}
});
notebook_css_patch(¬ebook);
notebook
};
let g_box = {
use gtk::{Box, Orientation, prelude::BoxExt};
let g_box = {
const MARGIN: i32 = 8;
Box::builder()
.margin_end(MARGIN)
.margin_start(MARGIN)
.orientation(Orientation::Vertical)
.spacing(MARGIN)
.build()
};
g_box.append(¬ebook);
g_box.append(&control.g_box);
g_box
};
text.text_view.add_controller({
const SHORTCUT: &str = "<Primary>Return"; let c = gtk::ShortcutController::new();
c.add_shortcut(
gtk::Shortcut::builder()
.trigger(>k::ShortcutTrigger::parse_string(SHORTCUT).unwrap())
.action(>k::CallbackAction::new({
let u = control.upload.clone();
move |_, _| {
if u.is_sensitive() {
u.emit_activate();
} else {
u.display().beep();
}
gtk::glib::Propagation::Stop
}
}))
.build(),
);
c
});
control.options.connect_clicked({
let text = text.clone();
let file = file.clone();
let notebook = notebook.clone();
move |this| {
use gtk::prelude::WidgetExt;
this.set_sensitive(false); let tab_number = notebook.current_page().unwrap();
match tab_number {
0 => text.header(),
1 => file.header(),
_ => panic!(),
}
.dialog(Some(this), {
let this = this.clone();
let text = text.clone();
let file = file.clone();
move |header| {
match tab_number {
0 => text.set_header(header),
1 => file.set_header(header),
_ => panic!(),
};
this.set_sensitive(true); }
})
}
});
control.upload.connect_clicked({
move |this| {
use control::Upload;
this.set_uploading();
let tab_number = notebook.current_page().unwrap();
callback(
match tab_number {
0 => text.header(),
1 => file.header(),
_ => panic!(),
},
match tab_number {
0 => text.bytes(),
1 => file.bytes().unwrap(),
_ => panic!(),
},
Box::new({
let this = this.clone();
move || this.set_resend() }),
)
}
});
g_box
}
}
fn notebook_css_patch(notebook: &Notebook) {
use gtk::prelude::WidgetExt;
let name = notebook.widget_name();
let provider = gtk::CssProvider::new();
provider.load_from_string(&format!(
"
#{name} stack {{
background: transparent;
}}
#{name} header {{
border-bottom-color: transparent;
}}
#{name} tab {{
opacity: 0.9;
}}
"
));
gtk::style_context_add_provider_for_display(
¬ebook.display(),
&provider,
gtk::STYLE_PROVIDER_PRIORITY_APPLICATION,
);
}