Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/remove_demo/main.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
pub mod child_widget;
pub mod remove_widget;
pub mod split_pane_layout;
pub mod stack_widget;

use remove_widget::RemoveWidget;
Expand Down
58 changes: 57 additions & 1 deletion examples/remove_demo/remove_widget.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ use tmui::{
widget::WidgetImpl,
};

use crate::{child_widget::ChildWidget, stack_widget::StackWidget};
use crate::{
child_widget::ChildWidget, split_pane_layout::SplitPaneLayout, stack_widget::StackWidget,
};

#[extends(Widget, Layout(VBox))]
#[derive(Childrenable)]
Expand All @@ -17,6 +19,8 @@ pub struct RemoveWidget {
bottom: Box<HBox>,
#[children]
stack: Box<StackWidget>,
#[children]
split_pane: Box<SplitPaneLayout>,

to_remove: ObjectId,
widget_id: ObjectId,
Expand All @@ -37,9 +41,17 @@ impl ObjectImpl for RemoveWidget {
let mut button_1 = Button::new(Some("Remove Left"));
let mut button_2 = Button::new(Some("Remove Right"));
let mut button_3 = Button::new(Some("Remove Stack"));
let mut button_4 = Button::new(Some("Remove SplitPane Left"));
let mut button_5 = Button::new(Some("Remove SplitPane RightTop"));
let mut button_6 = Button::new(Some("Remove SplitPane RightBottomLeft"));
let mut button_7 = Button::new(Some("Remove SplitPane RightBottomRight"));
button_1.width_request(100);
button_2.width_request(100);
button_3.width_request(100);
button_4.width_request(200);
button_5.width_request(200);
button_6.width_request(200);
button_7.width_request(200);
connect!(
button_1,
mouse_pressed(),
Expand All @@ -58,9 +70,37 @@ impl ObjectImpl for RemoveWidget {
self,
remove_stack_widget(MouseEvent)
);
connect!(
button_4,
mouse_pressed(),
self,
remove_split_pane_left(MouseEvent)
);
connect!(
button_5,
mouse_pressed(),
self,
remove_split_pane_right_top(MouseEvent)
);
connect!(
button_6,
mouse_pressed(),
self,
remove_split_pane_right_bottom_left(MouseEvent)
);
connect!(
button_7,
mouse_pressed(),
self,
remove_split_pane_right_bottom_right(MouseEvent)
);
self.top.add_child(button_1);
self.top.add_child(button_2);
self.top.add_child(button_3);
self.top.add_child(button_4);
self.top.add_child(button_5);
self.top.add_child(button_6);
self.top.add_child(button_7);

self.bottom.add_child(Label::new(Some("Label 1")));
let label2 = Label::new(Some("Label 2"));
Expand Down Expand Up @@ -99,4 +139,20 @@ impl RemoveWidget {
pub fn remove_stack_widget(&mut self, _: MouseEvent) {
self.stack.remove_index(1);
}

pub fn remove_split_pane_left(&mut self, _: MouseEvent) {
self.split_pane.remove_left();
}

pub fn remove_split_pane_right_top(&mut self, _: MouseEvent) {
self.split_pane.remove_right_top();
}

pub fn remove_split_pane_right_bottom_left(&mut self, _: MouseEvent) {
self.split_pane.remove_right_bottom_left();
}

pub fn remove_split_pane_right_bottom_right(&mut self, _: MouseEvent) {
self.split_pane.remove_right_bottom_right();
}
}
107 changes: 107 additions & 0 deletions examples/remove_demo/split_pane_layout.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
use std::ptr::NonNull;
use tlib::{connect, events::MouseEvent};
use tmui::{
label::Label,
prelude::*,
tlib::object::{ObjectImpl, ObjectSubclass},
widget::WidgetImpl,
};

#[extends(Widget, Layout(SplitPane))]
pub struct SplitPaneLayout {
left: ObjectId,
right_top: ObjectId,
right_bottom_left: ObjectId,
right_bottom_right: ObjectId,
cnt: i32,
label: Option<NonNull<Label>>,
}

impl ObjectSubclass for SplitPaneLayout {
const NAME: &'static str = "SplitPaneLayout";
}

impl ObjectImpl for SplitPaneLayout {
fn construct(&mut self) {
self.parent_construct();

let mut label = Label::new(Some("Click to split."));
label.set_size(20);
label.set_background(Color::RED);
label.set_content_halign(Align::Center);
label.set_content_valign(Align::Center);
label.set_mouse_tracking(true);
self.left = label.id();

connect!(label, mouse_pressed(), self, split_off(MouseEvent));
self.add_child(label);

let mut children_mut = self.children_mut();
let label = children_mut[0].downcast_mut::<Label>().unwrap();
self.label = NonNull::new(label);

self.width_request(400);
self.height_request(300);
self.set_render_difference(true);
}
}

impl WidgetImpl for SplitPaneLayout {}

impl SplitPaneLayout {
pub fn remove_left(&mut self) {
self.remove_children(self.left);
}

pub fn remove_right_top(&mut self) {
self.remove_children(self.right_top);
}

pub fn remove_right_bottom_left(&mut self) {
self.remove_children(self.right_bottom_left);
}

pub fn remove_right_bottom_right(&mut self) {
self.remove_children(self.right_bottom_right);
}

fn split_off(&mut self, _event: tlib::events::MouseEvent) {
if self.cnt != 0 {
return;
}
self.cnt += 1;

unsafe {
self.label
.as_mut()
.unwrap()
.as_mut()
.set_text("Split Left.")
};

let mut label_2 = Label::new(Some("Split right Top"));
label_2.set_size(20);
label_2.set_background(Color::GREEN);
label_2.set_content_halign(Align::Center);
label_2.set_content_valign(Align::Center);
self.right_top = label_2.id();

let mut label_3 = Label::new(Some("Split right Bottom-Left"));
label_3.set_size(20);
label_3.set_background(Color::YELLOW);
label_3.set_content_halign(Align::Center);
label_3.set_content_valign(Align::Center);
self.right_bottom_left = label_3.id();

let mut label_4 = Label::new(Some("Split right Bottom-Right"));
label_4.set_size(20);
label_4.set_background(Color::CYAN);
label_4.set_content_halign(Align::Center);
label_4.set_content_valign(Align::Center);
self.right_bottom_right = label_4.id();

self.split_right(self.left, label_2);
self.split_down(self.right_top, label_3);
self.split_right(self.right_bottom_left, label_4);
}
}
89 changes: 29 additions & 60 deletions macros/src/split_pane.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,14 @@ pub(crate) fn generate_split_pane_add_child() -> syn::Result<proc_macro2::TokenS

pub(crate) fn generate_split_pane_remove_children() -> syn::Result<proc_macro2::TokenStream> {
Ok(quote! {
// TODO
if let Some(index) = self.container.children.iter().position(|w| w.id() == id) {
let removed = self.container.children.remove(index);
self.close_pane(removed.id());

let window = ApplicationWindow::window();
window._add_removed_widget(removed);
window.layout_change(self);
}
})
}

Expand Down Expand Up @@ -78,68 +85,30 @@ pub(crate) fn generate_split_pane_impl(name: &Ident) -> syn::Result<proc_macro2:
}

fn close_pane(&mut self, id: ObjectId) {
use std::ptr::NonNull;
use std::collections::VecDeque;

if let Some(split_info) = self.split_infos.get_mut(&id) {
let remove_id_vec = if split_info.ty == SplitType::SplitNone {
let mut idx = 0;
let mut new_head = None;

// Make the second splitted widget to the head widget:
for split_to in split_info.split_to.iter_mut() {
let split_to_mut = nonnull_mut!(split_to);
if idx == 0 {
new_head = NonNull::new(split_to_mut);
split_to_mut.ty = SplitType::SplitNone;
} else {
let new_head_mut = unsafe { new_head.as_mut().unwrap().as_mut() };
new_head_mut.split_to.push(NonNull::new(split_to_mut));
split_to_mut.split_from = new_head;
}

idx += 1;
}

vec![split_info.id]
} else {
let split_from = split_from!(split_info);
split_from
.split_to
.retain(|st| unsafe { st.as_ref().unwrap().as_ref().id != id });

let mut remove_id_collect = vec![];
let mut deque: VecDeque<&SplitInfo> = VecDeque::new();
deque.push_back(split_info);

while !deque.is_empty() {
let split_info = deque.pop_front().unwrap();
remove_id_collect.push(split_info.id);

for split_to in split_info.split_to.iter() {
if let Some(ptr) = split_to {
deque.push_back(unsafe { ptr.as_ref() })
}
}
}

remove_id_collect
};

for id in remove_id_vec.iter() {
self.split_infos.remove(id);
self.split_infos_vec
.retain(|st| unsafe { st.as_ref().unwrap().as_ref().id } != *id);
self.children_mut().retain(|child| child.id() != *id);
}
let mut split = match self.split_infos.remove(&id) {
Some(s) => s,
None => return,
};

let mut split_from = if split.split_from.is_some() {
Some(nonnull_mut!(split.split_from))
} else {
None
};
if let Some(split_from) = split_from.as_mut() {
split_from.split_to.retain(|s| nonnull_ref!(s).id != id);
}

for split_to_ptr in split.split_to.iter_mut() {
let split_to = nonnull_mut!(split_to_ptr);
split_to.split_from = split.split_from;
split_to.ty = split.ty;

// Tell the `ApplicationWindow` that widget's layout has changed:
if self.window_id() == 0 {
panic!("`close_pane()` in SplitPane should invoke after window initialize.")
if let Some(split_from) = split_from.as_mut() {
split_from.split_to.push(split_to_ptr.clone());
}
ApplicationWindow::window_of(self.window_id()).layout_change(self);
self.update()
}
self.split_infos_vec.retain(|s| nonnull_ref!(s).id != id);
}

fn split<T: WidgetImpl>(&mut self, id: ObjectId, mut widget: Box<T>, ty: SplitType) {
Expand Down
12 changes: 7 additions & 5 deletions tmui/src/split_pane.rs
Original file line number Diff line number Diff line change
Expand Up @@ -149,39 +149,41 @@ pub trait SplitInfosGetter {
pub trait SplitPaneExt {
/// Split new widget left.
///
/// @param: id the id of target widget where user click on. <br>
/// @param: id the id of split base widget. <br>
/// @param widget the new widget that split off. <br>
///
/// @reutrn success or not.
fn split_left<T: WidgetImpl>(&mut self, id: ObjectId, widget: Box<T>);

/// Split new widget up.
///
/// @param: id the id of target widget where user click on. <br>
/// @param: id the id of split base widget. <br>
/// @param widget the new widget that split off. <br>
///
/// @reutrn success or not.
fn split_up<T: WidgetImpl>(&mut self, id: ObjectId, widget: Box<T>);

/// Split new widget right.
///
/// @param: id the id of target widget where user click on. <br>
/// @param: id the id of split base widget. <br>
/// @param widget the new widget that split off. <br>
///
/// @reutrn success or not.
fn split_right<T: WidgetImpl>(&mut self, id: ObjectId, widget: Box<T>);

/// Split new widget down.
///
/// @param: id the id of target widget where user click on. <br>
/// @param: id the id of split base widget. <br>
/// @param widget the new widget that split off. <br>
///
/// @reutrn success or not.
fn split_down<T: WidgetImpl>(&mut self, id: ObjectId, widget: Box<T>);

/// **Do not call this function directly, use `remove_children()` instead.**
///
/// Close the split pane, the widgets were splited from this pane will be closed automatically.
///
/// @param: id the id of target widget where user click on. <br>
/// @param: id the id of target widget to close. <br>
fn close_pane(&mut self, id: ObjectId);

/// Common function of split().
Expand Down