mirror of
https://github.com/YGGverse/Yoda.git
synced 2026-03-31 08:35:28 +00:00
use separated headers for tabs, use plain/text by default for text
This commit is contained in:
parent
0caca74efe
commit
005b7574ca
5 changed files with 147 additions and 88 deletions
|
|
@ -17,17 +17,13 @@ pub trait Titan {
|
|||
|
||||
impl Titan for gtk::Box {
|
||||
fn titan(callback: impl Fn(Header, Bytes, Box<dyn Fn()>) + 'static) -> Self {
|
||||
use gtk::{glib::uuid_string_random, prelude::ButtonExt, Label, TextView};
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
use gtk::{glib::uuid_string_random, prelude::ButtonExt, Label};
|
||||
use std::rc::Rc;
|
||||
|
||||
// Init components
|
||||
let header = Rc::new(RefCell::new(Header {
|
||||
mime: None,
|
||||
token: None,
|
||||
}));
|
||||
let control = Rc::new(Control::build(&header));
|
||||
let control = Rc::new(Control::build());
|
||||
let file = Rc::new(File::build(&control));
|
||||
let text = TextView::text(&control);
|
||||
let text = Rc::new(Text::build(&control));
|
||||
|
||||
let notebook = {
|
||||
let notebook = Notebook::builder()
|
||||
|
|
@ -35,7 +31,7 @@ impl Titan for gtk::Box {
|
|||
.show_border(false)
|
||||
.build();
|
||||
|
||||
notebook.append_page(&text, Some(&Label::tab("Text")));
|
||||
notebook.append_page(&text.text_view, Some(&Label::tab("Text")));
|
||||
notebook.append_page(&file.button, Some(&Label::tab("File")));
|
||||
|
||||
notebook.connect_switch_page({
|
||||
|
|
@ -75,21 +71,57 @@ impl Titan for gtk::Box {
|
|||
};
|
||||
|
||||
// Init events
|
||||
control.upload.connect_clicked(move |this| {
|
||||
use control::Upload;
|
||||
this.set_uploading();
|
||||
callback(
|
||||
header.borrow().clone(), // keep original header to have re-send ability
|
||||
match notebook.current_page().unwrap() {
|
||||
0 => text.to_bytes(),
|
||||
1 => file.to_bytes().unwrap(),
|
||||
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); // lock
|
||||
let page = notebook.current_page().unwrap();
|
||||
match page {
|
||||
0 => text.header(),
|
||||
1 => file.header(),
|
||||
_ => panic!(),
|
||||
},
|
||||
Box::new({
|
||||
}
|
||||
.dialog(Some(this), {
|
||||
let this = this.clone();
|
||||
move || this.set_resend() // re-activate button on failure
|
||||
}),
|
||||
)
|
||||
let text = text.clone();
|
||||
let file = file.clone();
|
||||
move |header| {
|
||||
match page {
|
||||
0 => text.set_header(header),
|
||||
1 => file.set_header(header),
|
||||
_ => panic!(),
|
||||
};
|
||||
this.set_sensitive(true); // unlock
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
control.upload.connect_clicked({
|
||||
move |this| {
|
||||
use control::Upload;
|
||||
this.set_uploading();
|
||||
let page = notebook.current_page().unwrap();
|
||||
callback(
|
||||
match page {
|
||||
0 => text.header(),
|
||||
1 => file.header(),
|
||||
_ => panic!(),
|
||||
},
|
||||
match page {
|
||||
0 => text.bytes(),
|
||||
1 => file.bytes().unwrap(),
|
||||
_ => panic!(),
|
||||
},
|
||||
Box::new({
|
||||
let this = this.clone();
|
||||
move || this.set_resend() // re-activate button on failure
|
||||
}),
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
g_box
|
||||
|
|
|
|||
|
|
@ -2,18 +2,17 @@ mod counter;
|
|||
mod options;
|
||||
mod upload;
|
||||
|
||||
use super::Header;
|
||||
use counter::Counter;
|
||||
use gtk::{
|
||||
prelude::{BoxExt, WidgetExt},
|
||||
Align, Box, Button, Label, Orientation,
|
||||
};
|
||||
use options::Options;
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
pub use upload::Upload;
|
||||
|
||||
pub struct Control {
|
||||
pub counter: Label,
|
||||
pub options: Button,
|
||||
pub upload: Button,
|
||||
pub g_box: Box,
|
||||
}
|
||||
|
|
@ -22,10 +21,10 @@ impl Control {
|
|||
// Constructors
|
||||
|
||||
/// Build new `Self`
|
||||
pub fn build(header: &Rc<RefCell<Header>>) -> Self {
|
||||
pub fn build() -> Self {
|
||||
// Init components
|
||||
let counter = Label::counter();
|
||||
let options = Button::options(header);
|
||||
let options = Button::options();
|
||||
let upload = Button::upload();
|
||||
|
||||
// Init main widget
|
||||
|
|
@ -46,6 +45,7 @@ impl Control {
|
|||
// Return activated struct
|
||||
Self {
|
||||
counter,
|
||||
options,
|
||||
upload,
|
||||
g_box,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,36 +1,14 @@
|
|||
use super::Header;
|
||||
use gtk::{
|
||||
prelude::{ButtonExt, WidgetExt},
|
||||
Button,
|
||||
};
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
use gtk::Button;
|
||||
|
||||
pub trait Options {
|
||||
fn options(header: &Rc<RefCell<Header>>) -> Self;
|
||||
fn options() -> Self;
|
||||
}
|
||||
|
||||
impl Options for Button {
|
||||
fn options(header: &Rc<RefCell<Header>>) -> Self {
|
||||
let button = Button::builder()
|
||||
fn options() -> Self {
|
||||
Button::builder()
|
||||
.icon_name("emblem-system-symbolic")
|
||||
.tooltip_text("Options")
|
||||
.build();
|
||||
|
||||
button.connect_clicked({
|
||||
let header = header.clone();
|
||||
move |this| {
|
||||
this.set_sensitive(false); // lock
|
||||
header.take().dialog(Some(this), {
|
||||
let this = this.clone();
|
||||
let header = header.clone();
|
||||
move |options| {
|
||||
header.replace(options);
|
||||
this.set_sensitive(true); // unlock
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
button
|
||||
.build()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
use super::Control;
|
||||
use super::{Control, Header};
|
||||
use gtk::{glib::Bytes, Button};
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
pub struct File {
|
||||
header: Rc<RefCell<Header>>,
|
||||
buffer: Rc<RefCell<Option<Bytes>>>,
|
||||
pub button: Button,
|
||||
}
|
||||
|
|
@ -16,6 +17,11 @@ impl File {
|
|||
};
|
||||
|
||||
// Init components
|
||||
let header = Rc::new(RefCell::new(Header {
|
||||
mime: None,
|
||||
token: None,
|
||||
}));
|
||||
|
||||
let buffer = Rc::new(RefCell::new(None));
|
||||
|
||||
let button = Button::builder()
|
||||
|
|
@ -77,21 +83,37 @@ impl File {
|
|||
}
|
||||
});
|
||||
|
||||
Self { buffer, button }
|
||||
Self {
|
||||
header,
|
||||
buffer,
|
||||
button,
|
||||
}
|
||||
}
|
||||
|
||||
/* this method is less-expensive but not useful as user
|
||||
will not able re-upload existing form on failure @TODO
|
||||
// Getters
|
||||
|
||||
pub fn take_bytes(&self) -> Option<Bytes> {
|
||||
self.buffer.borrow_mut().take()
|
||||
} */
|
||||
/// Get `Header` copy
|
||||
/// * borrow, do not take to have form re-send ability
|
||||
pub fn header(&self) -> Header {
|
||||
self.header.borrow().clone()
|
||||
}
|
||||
|
||||
pub fn to_bytes(&self) -> Option<Bytes> {
|
||||
/// Get cloned [Bytes](https://docs.gtk.org/glib/struct.Bytes.html)
|
||||
// * borrow, do not take to have form re-send ability
|
||||
pub fn bytes(&self) -> Option<Bytes> {
|
||||
self.buffer.borrow().as_ref().map(|bytes| bytes.clone())
|
||||
}
|
||||
|
||||
/// Get size
|
||||
pub fn size(&self) -> Option<usize> {
|
||||
self.buffer.borrow().as_ref().map(|bytes| bytes.len())
|
||||
}
|
||||
|
||||
// Setters
|
||||
|
||||
/// Replace current `Header`
|
||||
/// * return previous object
|
||||
pub fn set_header(&self, header: Header) -> Header {
|
||||
self.header.replace(header)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,55 +1,82 @@
|
|||
mod form;
|
||||
|
||||
use super::Control;
|
||||
use super::{Control, Header};
|
||||
use gtk::{
|
||||
glib::{Bytes, GString},
|
||||
prelude::{TextBufferExt, TextViewExt},
|
||||
TextView,
|
||||
TextBuffer, TextView,
|
||||
};
|
||||
use std::rc::Rc;
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
pub trait Text {
|
||||
fn text(control: &Rc<Control>) -> Self;
|
||||
fn to_bytes(&self) -> Bytes;
|
||||
fn to_gstring(&self) -> GString;
|
||||
fn len(&self) -> usize;
|
||||
fn count(&self) -> i32;
|
||||
pub struct Text {
|
||||
header: Rc<RefCell<Header>>,
|
||||
pub text_view: TextView,
|
||||
}
|
||||
|
||||
impl Text for TextView {
|
||||
fn text(control: &Rc<Control>) -> Self {
|
||||
impl Text {
|
||||
// Constructors
|
||||
|
||||
/// Build new `Self`
|
||||
pub fn build(control: &Rc<Control>) -> Self {
|
||||
use form::Form;
|
||||
|
||||
// Init components
|
||||
let header = Rc::new(RefCell::new(Header {
|
||||
mime: Some("text/plain".into()), // some servers may reject request without MIME @TODO optional defaults
|
||||
token: None,
|
||||
}));
|
||||
|
||||
// Init main widget
|
||||
let text_view = TextView::form();
|
||||
|
||||
text_view.buffer().connect_changed({
|
||||
let control = control.clone();
|
||||
let text_view = text_view.clone();
|
||||
move |text_buffer| control.update(Some(text_view.len()), Some(text_buffer.char_count()))
|
||||
move |text_buffer| {
|
||||
control.update(
|
||||
Some(gstring(text_buffer).len()),
|
||||
Some(text_buffer.char_count()),
|
||||
)
|
||||
}
|
||||
});
|
||||
|
||||
text_view
|
||||
Self { header, text_view }
|
||||
}
|
||||
|
||||
fn to_bytes(&self) -> Bytes {
|
||||
Bytes::from(self.to_gstring().as_bytes())
|
||||
// Getters
|
||||
|
||||
/// Get `Header` copy
|
||||
/// * borrow, do not take to have form re-send ability
|
||||
pub fn header(&self) -> Header {
|
||||
self.header.borrow().clone()
|
||||
}
|
||||
|
||||
fn to_gstring(&self) -> GString {
|
||||
let buffer = self.buffer();
|
||||
self.buffer()
|
||||
.text(&buffer.start_iter(), &buffer.end_iter(), true)
|
||||
pub fn bytes(&self) -> Bytes {
|
||||
Bytes::from(self.gstring().as_bytes())
|
||||
}
|
||||
|
||||
fn count(&self) -> i32 {
|
||||
self.buffer().char_count()
|
||||
pub fn gstring(&self) -> GString {
|
||||
gstring(&self.text_view.buffer())
|
||||
}
|
||||
|
||||
fn len(&self) -> usize {
|
||||
let buffer = self.buffer();
|
||||
pub fn count(&self) -> i32 {
|
||||
self.text_view.buffer().char_count()
|
||||
}
|
||||
|
||||
buffer
|
||||
.text(&buffer.start_iter(), &buffer.end_iter(), true)
|
||||
.len()
|
||||
pub fn len(&self) -> usize {
|
||||
self.gstring().len()
|
||||
}
|
||||
|
||||
// Setters
|
||||
|
||||
/// Replace current `Header`
|
||||
/// * return previous object
|
||||
pub fn set_header(&self, header: Header) -> Header {
|
||||
self.header.replace(header)
|
||||
}
|
||||
}
|
||||
|
||||
// Tools
|
||||
|
||||
fn gstring(text_buffer: &TextBuffer) -> GString {
|
||||
text_buffer.text(&text_buffer.start_iter(), &text_buffer.end_iter(), true)
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue