draggable tabs
This commit is contained in:
parent
f9a712fea4
commit
c508a18941
|
@ -1 +1 @@
|
|||
{"categories":[{"name":"to do","content":[{"name":"update workflow .yml","description":"make a workflow compiling the calcifer and put the linux in calcifer-{version}\nand the windows in calcifer_windows_{version}\n\nupdate nix\nupdate jiji","id":5},{"name":"repair build.rs","description":"// Hello there","id":1},{"name":"draggable tabs","description":"// Hello there","id":2}]},{"name":"in progress","content":[{"name":"export copy paste fix","description":"// Hello there","id":1}]},{"name":"done","content":[{"name":"move .project file","description":"// Hello there","id":4},{"name":"move config","description":"config from .calcifer/save.json\nto .config/calcifer/state.json","id":1},{"name":"add id to textarea per tab","description":"to improve undo, make each code area of each tab have a unique id (no more undo into another tab)","id":1},{"name":"file tree id ?","description":"// Hello there","id":1},{"name":"open dir in tree ?","description":"// Hello there","id":2},{"name":"fix tab title","description":"// Hello there","id":2},{"name":"when closing last tab","description":"close tab and THEN close calcifer (to save no tab in save.json)","id":1}]},{"name":"+","content":[]}]}
|
||||
{"categories":[{"name":"to do","content":[{"name":"update workflow .yml","description":"make a workflow compiling the calcifer and put the linux in calcifer-{version}\nand the windows in calcifer_windows_{version}\n\nupdate nix\nupdate jiji","id":5}]},{"name":"in progress","content":[]},{"name":"done","content":[{"name":"move .project file","description":"// Hello there","id":4},{"name":"move config","description":"config from .calcifer/save.json\nto .config/calcifer/state.json","id":1},{"name":"add id to textarea per tab","description":"to improve undo, make each code area of each tab have a unique id (no more undo into another tab)","id":1},{"name":"file tree id ?","description":"// Hello there","id":1},{"name":"open dir in tree ?","description":"// Hello there","id":2},{"name":"fix tab title","description":"// Hello there","id":2},{"name":"when closing last tab","description":"close tab and THEN close calcifer (to save no tab in save.json)","id":1},{"name":"draggable tabs","description":"// Hello there","id":2},{"name":"repair build.rs","description":"// Hello there","id":1},{"name":"export copy paste fix","description":"// Hello there","id":1}]},{"name":"+","content":[]}]}
|
|
@ -1,6 +1,6 @@
|
|||
use eframe::egui;
|
||||
use egui::Color32;
|
||||
use std::{cmp::min, fs, path::Path, path::PathBuf};
|
||||
use std::{cmp::min, cmp::max, fs, path::Path, path::PathBuf};
|
||||
|
||||
use crate::core;
|
||||
use crate::editor::themes::DEFAULT_THEMES;
|
||||
|
@ -238,6 +238,10 @@ impl Calcifer {
|
|||
|
||||
false
|
||||
}
|
||||
|
||||
pub fn tab_area_size(&self) -> usize {
|
||||
max(6, self.tabs.len() + 1)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::unnecessary_lazy_evaluations)]
|
||||
|
|
105
src/core/ui.rs
105
src/core/ui.rs
|
@ -208,8 +208,8 @@ impl Calcifer {
|
|||
0.0,
|
||||
core::hex_str_to_color(self.theme.bg),
|
||||
);
|
||||
StripBuilder::new(ui)
|
||||
.sizes(Size::remainder(), max(6, self.tabs.len() + 1))
|
||||
let response = StripBuilder::new(ui)
|
||||
.sizes(Size::remainder(), self.tab_area_size())
|
||||
.sense(egui::Sense::click())
|
||||
.horizontal(|mut strip| {
|
||||
for (index, tab) in self.tabs.clone().iter().enumerate() {
|
||||
|
@ -280,6 +280,7 @@ impl Calcifer {
|
|||
}
|
||||
});
|
||||
});
|
||||
self.tab_rect = response.rect;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -444,6 +445,87 @@ impl Calcifer {
|
|||
|
||||
self.handle_confirm();
|
||||
}
|
||||
|
||||
pub fn draw_mouse_drag(&mut self, ctx: &egui::Context) {
|
||||
if ctx.input(|i| i.pointer.is_decidedly_dragging()) {
|
||||
if let Some(pos) = ctx.input(|i| i.pointer.interact_pos()) {
|
||||
match self.mouse_holder {
|
||||
panels::MouseHolder::TabHolder(index) => {
|
||||
egui::Area::new(egui::Id::new("mouse_holder"))
|
||||
.fixed_pos(pos)
|
||||
.show(ctx, |ui| {
|
||||
let (bg_color, text_color) = if self.selected_tab == index {
|
||||
(core::hex_str_to_color(self.theme.functions), core::hex_str_to_color(self.theme.bg))
|
||||
} else {
|
||||
(core::hex_str_to_color(self.theme.bg), core::hex_str_to_color(self.theme.comments))
|
||||
};
|
||||
|
||||
|
||||
let rect = egui::Rect::from_center_size(
|
||||
egui::Pos2::new(pos.x, (self.tab_rect.max.y + self.tab_rect.min.y) / 2.0),
|
||||
egui::Vec2::new((self.tab_rect.max.x - self.tab_rect.min.x) / usize_to_f32(self.tab_area_size()), self.tab_rect.max.y - self.tab_rect.min.y)
|
||||
);
|
||||
|
||||
ui.painter().rect_filled(
|
||||
rect,
|
||||
0.0,
|
||||
bg_color,
|
||||
);
|
||||
let unsaved_indicator = if self.tabs[index].saved { "" } else { "~ " };
|
||||
|
||||
let _ = ui.put(rect, egui::Label::new(egui::RichText::new(format!(" {}{}", unsaved_indicator, self.tabs[index].get_name())).color(text_color)));
|
||||
});
|
||||
}
|
||||
panels::MouseHolder::None => {
|
||||
if self.tab_rect.distance_to_pos(pos) == 0.0 {
|
||||
let hover_pos : f32 = (pos.x - self.tab_rect.min.x) / ((self.tab_rect.max.x - self.tab_rect.min.x) / usize_to_f32(self.tab_area_size()));
|
||||
|
||||
if let Some(index) = floor_f32(hover_pos) {
|
||||
if index < self.tabs.len() {
|
||||
self.mouse_holder = panels::MouseHolder::TabHolder(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
match self.mouse_holder {
|
||||
panels::MouseHolder::TabHolder(initial_index) => {
|
||||
if let Some(pos) = ctx.input(|i| i.pointer.interact_pos()) {
|
||||
if self.tab_rect.distance_to_pos(pos) == 0.0 {
|
||||
let hover_pos : f32 = (pos.x - self.tab_rect.min.x) / ((self.tab_rect.max.x - self.tab_rect.min.x) / usize_to_f32(self.tab_area_size()));
|
||||
|
||||
if let Some(final_index) = floor_f32(hover_pos) {
|
||||
if final_index == initial_index {
|
||||
return
|
||||
} else if final_index < initial_index {
|
||||
self.tabs.insert(final_index, self.tabs[initial_index].clone());
|
||||
self.tabs.remove(initial_index + 1);
|
||||
} else {
|
||||
self.tabs.insert(final_index + 1, self.tabs[initial_index].clone());
|
||||
self.tabs.remove(initial_index);
|
||||
}
|
||||
|
||||
if self.selected_tab == initial_index {
|
||||
self.selected_tab = final_index;
|
||||
} else if self.selected_tab < initial_index && self.selected_tab >= final_index {
|
||||
self.selected_tab += 1;
|
||||
} else if self.selected_tab > initial_index && self.selected_tab <= final_index {
|
||||
self.selected_tab -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
panels::MouseHolder::None => {}
|
||||
}
|
||||
|
||||
self.mouse_holder = panels::MouseHolder::None;
|
||||
}
|
||||
}
|
||||
|
||||
fn to_syntax(language: &str) -> Syntax {
|
||||
|
@ -476,3 +558,22 @@ pub fn format_path(path: &Path) -> String {
|
|||
.join("/")
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
fn usize_to_f32(value: usize) -> f32 {
|
||||
const MAX_F32: f32 = f32::MAX;
|
||||
|
||||
if value as f64 > MAX_F32 as f64 {
|
||||
MAX_F32
|
||||
} else {
|
||||
value as f32
|
||||
}
|
||||
}
|
||||
|
||||
fn floor_f32(value: f32) -> Option<usize> {
|
||||
if value.is_nan() || value < 0.0 || value > usize::MAX as f32 {
|
||||
None
|
||||
} else {
|
||||
Some(value.floor() as usize)
|
||||
}
|
||||
}
|
|
@ -76,6 +76,8 @@ struct Calcifer {
|
|||
|
||||
selected_tab: usize,
|
||||
tabs: Vec<panels::Tab>,
|
||||
tab_rect: egui::Rect,
|
||||
mouse_holder: panels::MouseHolder,
|
||||
|
||||
command: String,
|
||||
command_history: Vec<panels::CommandEntry>,
|
||||
|
@ -117,6 +119,8 @@ impl Default for Calcifer {
|
|||
|
||||
selected_tab: 0,
|
||||
tabs: vec![panels::Tab::default()],
|
||||
tab_rect: egui::Rect::EVERYTHING,
|
||||
mouse_holder: panels::MouseHolder::None,
|
||||
|
||||
command: String::new(),
|
||||
command_history: Vec::new(),
|
||||
|
@ -305,6 +309,7 @@ impl eframe::App for Calcifer {
|
|||
watch = time::Instant::now();
|
||||
|
||||
self.draw_windows(ctx);
|
||||
self.draw_mouse_drag(ctx);
|
||||
|
||||
self.time_watch[6] = watch.elapsed().as_micros() as f32 / 1000.0;
|
||||
|
||||
|
|
|
@ -61,6 +61,11 @@ impl Tab {
|
|||
}
|
||||
}
|
||||
|
||||
pub enum MouseHolder {
|
||||
TabHolder(usize),
|
||||
None,
|
||||
}
|
||||
|
||||
fn read_file_contents(path: &Path) -> String {
|
||||
let error_type = "reading file";
|
||||
read_to_string(path)
|
||||
|
|
Loading…
Reference in a new issue