closable_tabs2/
closable_tabs2.rs1#![allow(dead_code)]
4
5mod closable_tab {
6 use fltk::{
7 app, button,
8 enums::{Align, Color, FrameType},
9 group,
10 prelude::*,
11 };
12
13 #[derive(Copy, Clone)]
14 pub enum Message {
15 Foreground(i32),
16 Delete(i32),
17 InsertNew(i32),
18 }
19
20 fn create_tab_button(label: &str) -> group::Group {
21 let mut grp = group::Group::new(0, 0, 150, 40, None);
22 grp.set_align(Align::Left | Align::Inside);
23 let mut but_handle = button::Button::new(grp.x() + 5, grp.y() + 5, 110, 30, "");
24 but_handle.set_align(Align::Left | Align::Inside);
25 but_handle.set_label(label);
26 let mut but_close = button::Button::new(grp.x() + 120, grp.y() + 10, 20, 20, "@1+");
27 but_handle.set_frame(FrameType::FlatBox);
28 but_handle.clear_visible_focus();
29 but_close.set_frame(FrameType::FlatBox);
30 grp.end();
31 grp.set_frame(FrameType::UpFrame);
32 grp
33 }
34
35 pub struct ClosableTab<'a> {
37 current: Option<i32>, snd: &'a app::Sender<Message>,
39 contents: group::Group,
40 tab_labels: group::Pack,
41 }
42
43 impl<'a> ClosableTab<'a> {
44 pub fn new(x: i32, y: i32, w: i32, h: i32, snd: &'a app::Sender<Message>) -> Self {
45 let current = None;
46 let parent_grp = group::Group::new(x, y, w, h, None);
47 let mut tab_labels = group::Pack::new(x + 5, y, w - 10, 40, None);
48 tab_labels.set_spacing(3);
49 tab_labels.set_type(group::PackType::Horizontal);
50 tab_labels.end();
51 let mut contents = group::Group::new(x, y + 40, w, h - 40, None);
52 contents.set_frame(FrameType::NoBox);
53 contents.end();
54 parent_grp.end();
55 Self {
56 current,
57 snd,
58 contents,
59 tab_labels,
60 }
61 }
62
63 pub fn add(&mut self, child: &mut group::Group, label: &str) {
64 child.resize(
65 self.contents.x(),
66 self.contents.y(),
67 self.contents.w(),
68 self.contents.h(),
69 );
70 self.contents.add(child);
71 let but = create_tab_button(label);
72 self.tab_labels.add(&but);
73 but.child(1).unwrap().set_callback({
74 let curr_child = child.clone();
75 let contents = self.contents.clone();
76 let sndb = *self.snd;
77 move |_| {
78 let idx = contents.find(&curr_child);
79 sndb.send(Message::Delete(idx));
80 app::redraw();
81 }
82 });
83 but.child(0).unwrap().set_callback({
84 let curr_child = child.clone();
85 let contents = self.contents.clone();
86 let sndb = *self.snd;
87 move |_| {
88 let idx = contents.find(&curr_child);
89 sndb.send(Message::Foreground(idx));
90 app::redraw();
91 }
92 });
93 }
94
95 pub fn remove(&mut self, idx: i32) {
96 self.contents.remove_by_index(idx);
97 self.tab_labels.remove_by_index(idx);
98 if self.current == Some(idx) {
99 if idx > 1 {
100 self.set_foreground(idx - 1);
101 } else if self.contents.children() > 0 {
102 self.set_foreground(0);
103 }
104 }
105 }
106
107 pub fn set_foreground(&mut self, fg_idx: i32) {
109 for idx in 0..self.contents.children() {
110 if idx != fg_idx {
111 self.contents.child(idx).unwrap().hide();
112 self.tab_labels
113 .child(idx)
114 .unwrap()
115 .set_label_color(fltk::enums::Color::Inactive);
116 self.tab_labels
117 .child(idx)
118 .unwrap()
119 .set_color(fltk::enums::Color::Inactive);
120 self.tab_labels
121 .child(idx)
122 .unwrap()
123 .set_frame(FrameType::DownFrame);
124 } else {
125 self.contents.child(idx).unwrap().show();
126 self.tab_labels
127 .child(idx)
128 .unwrap()
129 .set_label_color(Color::Selection);
130 self.tab_labels
131 .child(idx)
132 .unwrap()
133 .set_color(fltk::enums::Color::Selection);
134 self.tab_labels
135 .child(idx)
136 .unwrap()
137 .set_frame(FrameType::NoBox);
138 }
139 self.tab_labels.child(idx).unwrap().set_damage(true);
140 self.tab_labels.child(idx).unwrap().redraw();
141 self.current = Some(fg_idx);
142 }
143 }
144
145 pub fn get_foreground(&self) -> Option<i32> {
147 self.current
148 }
149 }
150}
151
152fn main() {
153 use fltk::{prelude::*, *};
154 pub fn create_tab(from: i32, to: i32) -> group::Group {
156 let grp = group::Group::new(0, 0, 800, 600, None);
157 for idx in from..to {
158 button::Button::new(
159 idx * 10 + (idx - from) * 42,
160 idx * 10 + (idx - from) * 42,
161 80,
162 40,
163 None,
164 )
165 .with_label(&format!("button {idx}"));
166 }
167 grp.end();
168 grp
169 }
170 let app = app::App::default();
171 let mut win = window::Window::default().with_size(800, 600);
172 let (s, r) = app::channel::<closable_tab::Message>();
173 let mut tabs = closable_tab::ClosableTab::new(0, 0, 800, 600, &s);
174 win.end();
175 win.show();
176 tabs.add(&mut create_tab(1, 3), "tab 1");
177 tabs.add(&mut create_tab(4, 7), "tab 2");
178 tabs.add(&mut create_tab(8, 11), "tab 3");
179 tabs.add(&mut create_tab(12, 15), "tab 4");
180 tabs.add(&mut create_tab(16, 22), "tab 5");
181 tabs.set_foreground(2);
182 while app.wait() {
183 use closable_tab::Message::*;
184 if let Some(msg) = r.recv() {
185 match msg {
186 Foreground(idx) => {
187 tabs.set_foreground(idx);
188 }
189 Delete(idx) => {
190 tabs.remove(idx);
191 }
192 InsertNew(_) => {}
193 }
194 }
195 }
196}