mirror of
https://github.com/emilk/egui.git
synced 2026-09-01 06:10:06 -04:00
refactored the viewports example
I added drag and drop on every viewport, to make possible in the future to drag and drop between viewports
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
use egui::mutex::RwLock;
|
use egui::mutex::RwLock;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use eframe::egui;
|
use eframe::egui::{self, InnerResponse};
|
||||||
use eframe::egui::ViewportBuilder;
|
use eframe::egui::{Id, ViewportBuilder};
|
||||||
use eframe::NativeOptions;
|
use eframe::NativeOptions;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
@@ -13,15 +13,9 @@ pub struct App {
|
|||||||
async_viewport_state: Arc<RwLock<usize>>,
|
async_viewport_state: Arc<RwLock<usize>>,
|
||||||
sync_viewport_state: usize,
|
sync_viewport_state: usize,
|
||||||
|
|
||||||
async_show_async_viewport: Arc<RwLock<bool>>,
|
|
||||||
async_show_sync_viewport: Arc<RwLock<bool>>,
|
|
||||||
|
|
||||||
async_async_viewport_state: Arc<RwLock<usize>>,
|
async_async_viewport_state: Arc<RwLock<usize>>,
|
||||||
async_sync_viewport_state: Arc<RwLock<usize>>,
|
async_sync_viewport_state: Arc<RwLock<usize>>,
|
||||||
|
|
||||||
sync_show_async_viewport: bool,
|
|
||||||
sync_show_sync_viewport: bool,
|
|
||||||
|
|
||||||
sync_async_viewport_state: Arc<RwLock<usize>>,
|
sync_async_viewport_state: Arc<RwLock<usize>>,
|
||||||
sync_sync_viewport_state: usize,
|
sync_sync_viewport_state: usize,
|
||||||
}
|
}
|
||||||
@@ -29,7 +23,7 @@ pub struct App {
|
|||||||
impl eframe::App for App {
|
impl eframe::App for App {
|
||||||
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
|
||||||
egui::CentralPanel::default().show(ctx, |ui| {
|
egui::CentralPanel::default().show(ctx, |ui| {
|
||||||
ui_info(ui);
|
generic_ui(ui, "Central Pannel");
|
||||||
ui.label("Look at the \"Frame: \" will tell you, what viewport is rendering!");
|
ui.label("Look at the \"Frame: \" will tell you, what viewport is rendering!");
|
||||||
{
|
{
|
||||||
let mut force_embedding = ctx.force_embedding();
|
let mut force_embedding = ctx.force_embedding();
|
||||||
@@ -40,215 +34,281 @@ impl eframe::App for App {
|
|||||||
ui.checkbox(&mut self.show_sync_viewport, "Show Sync Viewport");
|
ui.checkbox(&mut self.show_sync_viewport, "Show Sync Viewport");
|
||||||
|
|
||||||
let ctx = ui.ctx();
|
let ctx = ui.ctx();
|
||||||
|
|
||||||
// Showing Async Viewport
|
// Showing Async Viewport
|
||||||
if self.show_async_viewport {
|
if self.show_async_viewport {
|
||||||
let state = self.async_viewport_state.clone();
|
let async_state = self.async_async_viewport_state.clone();
|
||||||
|
let sync_state = self.async_sync_viewport_state.clone();
|
||||||
|
|
||||||
let show_async_viewport2 = self.async_show_async_viewport.clone();
|
show_async_viewport(
|
||||||
let show_sync_viewport2 = self.async_show_sync_viewport.clone();
|
ctx,
|
||||||
|
"Async Viewport",
|
||||||
let async_viewport_state2 = self.async_async_viewport_state.clone();
|
self.async_viewport_state.clone(),
|
||||||
let sync_viewport_state2 = self.async_sync_viewport_state.clone();
|
vec![
|
||||||
|
AsyncViewport::new("Async Viewport in Async Viewport", move |ctx| {
|
||||||
ctx.create_viewport(
|
show_async_viewport(
|
||||||
ViewportBuilder::new("Async Viewport").with_title("Async Viewport"),
|
ctx,
|
||||||
move |ctx| {
|
"AA Async Viewport in Async Viewport",
|
||||||
let mut state = state.write();
|
async_state.clone(),
|
||||||
|
vec![],
|
||||||
let mut show_async_viewport2 = show_async_viewport2.write();
|
);
|
||||||
let mut show_sync_viewport2 = show_sync_viewport2.write();
|
}),
|
||||||
|
AsyncViewport::new("Sync Viewport in Async Viewport", move |ctx| {
|
||||||
let async_viewport_state2 = async_viewport_state2.clone();
|
let mut state = sync_state.write();
|
||||||
let sync_viewport_state2 = sync_viewport_state2.clone();
|
show_sync_viewport(
|
||||||
|
ctx,
|
||||||
let content = move |ui: &mut egui::Ui| {
|
"AS Sync Viewport in Async Viewport",
|
||||||
ui_info(ui);
|
&mut state,
|
||||||
|
vec![],
|
||||||
ui.checkbox(&mut show_async_viewport2, "Show Async Viewport 2");
|
);
|
||||||
ui.checkbox(&mut show_sync_viewport2, "Show Sync Viewport 2");
|
}),
|
||||||
|
],
|
||||||
ui.label(format!("Count: {}", *state));
|
|
||||||
if ui.button("Add").clicked() {
|
|
||||||
*state += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if *show_async_viewport2 {
|
|
||||||
ctx.create_viewport(
|
|
||||||
ViewportBuilder::new("Async Viewport in Async Viewport")
|
|
||||||
.with_title("Async Viewport in Async Viewport"),
|
|
||||||
move |ctx| {
|
|
||||||
let mut state = async_viewport_state2.write();
|
|
||||||
|
|
||||||
let content = move |ui: &mut egui::Ui| {
|
|
||||||
ui_info(ui);
|
|
||||||
|
|
||||||
ui.label(format!("Count: {}", *state));
|
|
||||||
if ui.button("Add").clicked() {
|
|
||||||
*state += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ui.button("Set parent pos {0, 0}").clicked() {
|
|
||||||
let ctx = ui.ctx().clone();
|
|
||||||
let parent_id = ctx.parent_viewport_id();
|
|
||||||
ctx.viewport_command_for(
|
|
||||||
parent_id,
|
|
||||||
egui::ViewportCommand::OuterPosition(
|
|
||||||
egui::pos2(0.0, 0.0),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
show_as_popup(
|
|
||||||
ctx,
|
|
||||||
"Async Viewport in Async Viewport",
|
|
||||||
content,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if *show_sync_viewport2 {
|
|
||||||
ctx.create_viewport_sync(
|
|
||||||
ViewportBuilder::new("Sync Viewport in Async Viewport")
|
|
||||||
.with_title("Sync Viewport in Async Viewport"),
|
|
||||||
move |ctx| {
|
|
||||||
let mut state = sync_viewport_state2.write();
|
|
||||||
|
|
||||||
let content = move |ui: &mut egui::Ui| {
|
|
||||||
ui_info(ui);
|
|
||||||
|
|
||||||
ui.label(format!("Count: {}", *state));
|
|
||||||
if ui.button("Add").clicked() {
|
|
||||||
*state += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ui.button("Set parent pos {0, 0}").clicked() {
|
|
||||||
let ctx = ui.ctx().clone();
|
|
||||||
let parent_id = ctx.parent_viewport_id();
|
|
||||||
ctx.viewport_command_for(
|
|
||||||
parent_id,
|
|
||||||
egui::ViewportCommand::OuterPosition(
|
|
||||||
egui::pos2(0.0, 0.0),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
show_as_popup(
|
|
||||||
ctx,
|
|
||||||
"Sync Viewport in Async Viewport",
|
|
||||||
content,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
show_as_popup(ctx, "Async Viewport", content);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Showing Sync Viewport
|
// Showing Sync Viewport
|
||||||
if self.show_sync_viewport {
|
if self.show_sync_viewport {
|
||||||
ctx.create_viewport_sync(
|
let async_state = self.sync_async_viewport_state.clone();
|
||||||
ViewportBuilder::new("Sync Viewport").with_title("Sync Viewport"),
|
let sync_state = &mut self.sync_sync_viewport_state;
|
||||||
|ctx| {
|
show_sync_viewport(
|
||||||
let async_viewport_state3 = self.sync_async_viewport_state.clone();
|
ctx,
|
||||||
|
"Sync Viewport",
|
||||||
let content = |ui: &mut egui::Ui| {
|
&mut self.sync_viewport_state,
|
||||||
ui_info(ui);
|
vec![
|
||||||
|
SyncViewport::new("Async Viewport in Sync Viewport", move |ctx| {
|
||||||
ui.checkbox(&mut self.sync_show_async_viewport, "Show Async Viewport");
|
show_async_viewport(
|
||||||
ui.checkbox(&mut self.sync_show_sync_viewport, "Show Sync Viewport");
|
ctx,
|
||||||
|
"SA Async Viewport in Sync Viewport",
|
||||||
ui.label(format!("Count: {}", self.sync_viewport_state));
|
async_state.clone(),
|
||||||
if ui.button("Add").clicked() {
|
vec![],
|
||||||
self.sync_viewport_state += 1;
|
);
|
||||||
}
|
}),
|
||||||
|
SyncViewport::new("Sync Viewport in Sync Viewport", move |ctx| {
|
||||||
if self.sync_show_async_viewport {
|
show_sync_viewport(
|
||||||
ctx.create_viewport(
|
ctx,
|
||||||
ViewportBuilder::new("Async Viewport in Sync Viewport")
|
"SS Sync Viewport in Sync Viewport",
|
||||||
.with_title("Async Viewport in Sync Viewport"),
|
sync_state,
|
||||||
move |ctx| {
|
vec![],
|
||||||
let mut state = async_viewport_state3.write();
|
);
|
||||||
|
}),
|
||||||
let content = move |ui: &mut egui::Ui| {
|
],
|
||||||
ui_info(ui);
|
|
||||||
|
|
||||||
ui.label(format!("Count: {}", *state));
|
|
||||||
if ui.button("Add").clicked() {
|
|
||||||
*state += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ui.button("Set parent pos {0, 0}").clicked() {
|
|
||||||
let ctx = ui.ctx().clone();
|
|
||||||
let parent_id = ctx.parent_viewport_id();
|
|
||||||
ctx.viewport_command_for(
|
|
||||||
parent_id,
|
|
||||||
egui::ViewportCommand::OuterPosition(
|
|
||||||
egui::pos2(0.0, 0.0),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
show_as_popup(
|
|
||||||
ctx,
|
|
||||||
"Async Viewport in Sync Viewport",
|
|
||||||
content,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if self.sync_show_sync_viewport {
|
|
||||||
ctx.create_viewport_sync(
|
|
||||||
ViewportBuilder::new("Sync Viewport in Sync Viewport")
|
|
||||||
.with_title("Sync Viewport in Sync Viewport"),
|
|
||||||
move |ctx| {
|
|
||||||
let state = &mut self.sync_sync_viewport_state;
|
|
||||||
|
|
||||||
let content = move |ui: &mut egui::Ui| {
|
|
||||||
ui_info(ui);
|
|
||||||
|
|
||||||
ui.label(format!("Count: {}", *state));
|
|
||||||
if ui.button("Add").clicked() {
|
|
||||||
*state += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ui.button("Set parent pos {0, 0}").clicked() {
|
|
||||||
let ctx = ui.ctx().clone();
|
|
||||||
let parent_id = ctx.parent_viewport_id();
|
|
||||||
ctx.viewport_command_for(
|
|
||||||
parent_id,
|
|
||||||
egui::ViewportCommand::OuterPosition(
|
|
||||||
egui::pos2(0.0, 0.0),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
show_as_popup(
|
|
||||||
ctx,
|
|
||||||
"Sync Viewport in Sync Viewport",
|
|
||||||
content,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
show_as_popup(ctx, "Sync Viewport", content);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Clone)]
|
||||||
|
struct State {
|
||||||
|
active: Vec<bool>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct AsyncViewport {
|
||||||
|
name: String,
|
||||||
|
init: Arc<Box<dyn Fn(&egui::Context) + Sync + Send>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsyncViewport {
|
||||||
|
fn new(name: impl Into<String>, init: impl Fn(&egui::Context) + Sync + Send + 'static) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.into(),
|
||||||
|
init: Arc::new(Box::new(init)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_async_viewport(
|
||||||
|
ctx: &egui::Context,
|
||||||
|
name: impl Into<String>,
|
||||||
|
count: Arc<RwLock<usize>>,
|
||||||
|
viewports: Vec<AsyncViewport>,
|
||||||
|
) {
|
||||||
|
let name: String = name.into();
|
||||||
|
|
||||||
|
ctx.create_viewport(
|
||||||
|
ViewportBuilder::new(name.clone())
|
||||||
|
.with_title(name.as_str())
|
||||||
|
.with_inner_size(Some(egui::vec2(450.0, 320.0))),
|
||||||
|
move |ctx| {
|
||||||
|
let mut count = count.write();
|
||||||
|
let viewports = viewports.clone();
|
||||||
|
|
||||||
|
let n = name.clone();
|
||||||
|
let name = n.clone();
|
||||||
|
|
||||||
|
let content = move |ui: &mut egui::Ui| {
|
||||||
|
generic_ui(ui, name.clone());
|
||||||
|
|
||||||
|
let ctx = ui.ctx().clone();
|
||||||
|
let mut state = ctx.memory_mut(|mem| {
|
||||||
|
mem.data
|
||||||
|
.get_temp_mut_or_default::<State>(name.clone().into())
|
||||||
|
.clone()
|
||||||
|
});
|
||||||
|
|
||||||
|
state.active.resize(viewports.len(), false);
|
||||||
|
|
||||||
|
for (i, viewport) in viewports.iter().enumerate() {
|
||||||
|
ui.checkbox(&mut state.active[i], &viewport.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.add(egui::DragValue::new(&mut *count).prefix("Count: "));
|
||||||
|
if ui.button("Add").clicked() {
|
||||||
|
*count += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, viewport) in viewports.iter().enumerate() {
|
||||||
|
if state.active[i] {
|
||||||
|
(viewport.init)(&ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.memory_mut(move |mem| {
|
||||||
|
*mem.data.get_temp_mut_or_default::<State>(name.into()) = state;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
show_as_popup(ctx, &n, content);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SyncViewport<'a> {
|
||||||
|
name: String,
|
||||||
|
init: Box<dyn FnMut(&egui::Context) + 'a>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> SyncViewport<'a> {
|
||||||
|
fn new(name: impl Into<String>, init: impl FnMut(&egui::Context) + 'a) -> Self {
|
||||||
|
Self {
|
||||||
|
name: name.into(),
|
||||||
|
init: Box::new(init),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_sync_viewport(
|
||||||
|
ctx: &egui::Context,
|
||||||
|
name: impl Into<String>,
|
||||||
|
count: &mut usize,
|
||||||
|
mut viewports: Vec<SyncViewport<'_>>,
|
||||||
|
) {
|
||||||
|
let name: String = name.into();
|
||||||
|
|
||||||
|
ctx.create_viewport_sync(
|
||||||
|
ViewportBuilder::new(name.clone())
|
||||||
|
.with_title(name.as_str())
|
||||||
|
.with_inner_size(Some(egui::vec2(450.0, 320.0))),
|
||||||
|
move |ctx| {
|
||||||
|
let n = name.clone();
|
||||||
|
|
||||||
|
let content = |ui: &mut egui::Ui| {
|
||||||
|
generic_ui(ui, name.clone());
|
||||||
|
|
||||||
|
let ctx = ui.ctx().clone();
|
||||||
|
let mut state = ctx.memory_mut(|mem| {
|
||||||
|
mem.data
|
||||||
|
.get_temp_mut_or_default::<State>(name.clone().into())
|
||||||
|
.clone()
|
||||||
|
});
|
||||||
|
|
||||||
|
state.active.resize(viewports.len(), false);
|
||||||
|
|
||||||
|
for (i, viewport) in viewports.iter().enumerate() {
|
||||||
|
ui.checkbox(&mut state.active[i], &viewport.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.add(egui::DragValue::new(&mut *count).prefix("Count: "));
|
||||||
|
if ui.button("Add").clicked() {
|
||||||
|
*count += 1;
|
||||||
|
}
|
||||||
|
for (i, viewport) in viewports.iter_mut().enumerate() {
|
||||||
|
if state.active[i] {
|
||||||
|
(viewport.init)(&ctx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.memory_mut(move |mem| {
|
||||||
|
*mem.data.get_temp_mut_or_default::<State>(name.into()) = state;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
show_as_popup(ctx, &n, content);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is taken from crates/egui_demo_lib/src/debo/drag_and_drop.rs
|
||||||
|
fn drag_source<R>(
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
id: egui::Id,
|
||||||
|
body: impl FnOnce(&mut egui::Ui) -> R,
|
||||||
|
) -> InnerResponse<R> {
|
||||||
|
let is_being_dragged = ui.memory(|mem| mem.is_being_dragged(id));
|
||||||
|
|
||||||
|
if !is_being_dragged {
|
||||||
|
let res = ui.scope(body);
|
||||||
|
|
||||||
|
// Check for drags:
|
||||||
|
let response = ui.interact(res.response.rect, id, egui::Sense::drag());
|
||||||
|
if response.hovered() {
|
||||||
|
ui.ctx().set_cursor_icon(egui::CursorIcon::Grab);
|
||||||
|
}
|
||||||
|
res
|
||||||
|
} else {
|
||||||
|
ui.ctx().set_cursor_icon(egui::CursorIcon::Grabbing);
|
||||||
|
|
||||||
|
// Paint the body to a new layer:
|
||||||
|
let layer_id = egui::LayerId::new(egui::Order::Tooltip, id);
|
||||||
|
let res = ui.with_layer_id(layer_id, body);
|
||||||
|
|
||||||
|
if let Some(pointer_pos) = ui.ctx().pointer_interact_pos() {
|
||||||
|
let delta = pointer_pos - res.response.rect.center();
|
||||||
|
ui.ctx().translate_layer(layer_id, delta);
|
||||||
|
}
|
||||||
|
|
||||||
|
res
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is taken from crates/egui_demo_lib/src/debo/drag_and_drop.rs
|
||||||
|
fn drop_target<R>(
|
||||||
|
ui: &mut egui::Ui,
|
||||||
|
body: impl FnOnce(&mut egui::Ui) -> R,
|
||||||
|
) -> egui::InnerResponse<R> {
|
||||||
|
let is_being_dragged = ui.memory(|mem| mem.is_anything_being_dragged());
|
||||||
|
|
||||||
|
let margin = egui::Vec2::splat(ui.visuals().clip_rect_margin); // 3.0
|
||||||
|
|
||||||
|
let background_id = ui.painter().add(egui::Shape::Noop);
|
||||||
|
|
||||||
|
let avalibile_rect = ui.available_rect_before_wrap();
|
||||||
|
let inner_rect = avalibile_rect.shrink2(margin);
|
||||||
|
let mut content_ui = ui.child_ui(inner_rect, *ui.layout());
|
||||||
|
let ret = body(&mut content_ui);
|
||||||
|
|
||||||
|
let outer_rect =
|
||||||
|
egui::Rect::from_min_max(avalibile_rect.min, content_ui.min_rect().max + margin);
|
||||||
|
let (rect, response) = ui.allocate_at_least(outer_rect.size(), egui::Sense::hover());
|
||||||
|
|
||||||
|
let style = if is_being_dragged && response.hovered() {
|
||||||
|
ui.visuals().widgets.active
|
||||||
|
} else {
|
||||||
|
ui.visuals().widgets.inactive
|
||||||
|
};
|
||||||
|
|
||||||
|
let fill = style.bg_fill;
|
||||||
|
let stroke = style.bg_stroke;
|
||||||
|
|
||||||
|
ui.painter().set(
|
||||||
|
background_id,
|
||||||
|
egui::epaint::RectShape::new(rect, style.rounding, fill, stroke),
|
||||||
|
);
|
||||||
|
|
||||||
|
egui::InnerResponse::new(ret, response)
|
||||||
|
}
|
||||||
|
|
||||||
/// This will make the content as a popup if cannot has his own native window
|
/// This will make the content as a popup if cannot has his own native window
|
||||||
fn show_as_popup(ctx: &egui::Context, name: &str, content: impl FnOnce(&mut egui::Ui)) {
|
fn show_as_popup(ctx: &egui::Context, name: &str, content: impl FnOnce(&mut egui::Ui)) {
|
||||||
if ctx.viewport_id() == ctx.parent_viewport_id() {
|
if ctx.viewport_id() == ctx.parent_viewport_id() {
|
||||||
@@ -258,7 +318,7 @@ fn show_as_popup(ctx: &egui::Context, name: &str, content: impl FnOnce(&mut egui
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ui_info(ui: &mut egui::Ui) {
|
fn generic_ui(ui: &mut egui::Ui, container_id: impl Into<Id>) {
|
||||||
let ctx = ui.ctx().clone();
|
let ctx = ui.ctx().clone();
|
||||||
ui.label(format!("Frame: {}", ctx.frame_nr()));
|
ui.label(format!("Frame: {}", ctx.frame_nr()));
|
||||||
ui.label(format!("Current Viewport Id: {}", ctx.viewport_id()));
|
ui.label(format!("Current Viewport Id: {}", ctx.viewport_id()));
|
||||||
@@ -275,6 +335,122 @@ fn ui_info(ui: &mut egui::Ui) {
|
|||||||
outer_rect.min,
|
outer_rect.min,
|
||||||
outer_rect.size()
|
outer_rect.size()
|
||||||
));
|
));
|
||||||
|
|
||||||
|
let ctx = ui.ctx().clone();
|
||||||
|
if ctx.viewport_id() == ctx.parent_viewport_id() {
|
||||||
|
let parent = ctx.parent_viewport_id();
|
||||||
|
if ui.button("Set parent pos 0,0").clicked() {
|
||||||
|
ctx.viewport_command_for(
|
||||||
|
parent,
|
||||||
|
egui::ViewportCommand::OuterPosition(egui::pos2(0.0, 0.0)),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
|
let container_id = container_id.into();
|
||||||
|
|
||||||
|
const COLS: usize = 2;
|
||||||
|
static DATA: OnceLock<RwLock<DragAndDrop>> = OnceLock::new();
|
||||||
|
let data = DATA.get_or_init(Default::default);
|
||||||
|
data.write().init(container_id);
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct DragAndDrop {
|
||||||
|
containers_data: HashMap<Id, Vec<Vec<Id>>>,
|
||||||
|
data: HashMap<Id, String>,
|
||||||
|
counter: usize,
|
||||||
|
is_dragged: Option<Id>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DragAndDrop {
|
||||||
|
fn init(&mut self, container: Id) {
|
||||||
|
if !self.containers_data.contains_key(&container) {
|
||||||
|
for i in 0..COLS {
|
||||||
|
self.insert(
|
||||||
|
container,
|
||||||
|
i,
|
||||||
|
format!("From: {container:?}, and is: {}", self.counter),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn insert(&mut self, container: Id, col: usize, value: impl Into<String>) {
|
||||||
|
assert!(col <= COLS, "The coll should be less then: {COLS}");
|
||||||
|
|
||||||
|
let value: String = value.into();
|
||||||
|
let id = Id::new(format!("%{}% {}", self.counter, &value));
|
||||||
|
self.data.insert(id, value);
|
||||||
|
let viewport_data = self.containers_data.entry(container).or_insert_with(|| {
|
||||||
|
let mut res = Vec::new();
|
||||||
|
res.resize_with(COLS, Default::default);
|
||||||
|
res
|
||||||
|
});
|
||||||
|
self.counter += 1;
|
||||||
|
|
||||||
|
viewport_data[col].push(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cols(&self, container: Id, col: usize) -> Vec<(Id, String)> {
|
||||||
|
assert!(col <= COLS, "The col should be less then: {COLS}");
|
||||||
|
let container_data = &self.containers_data[&container];
|
||||||
|
container_data[col]
|
||||||
|
.iter()
|
||||||
|
.map(|id| (*id, self.data[id].clone()))
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Move element ID to Viewport and col
|
||||||
|
fn mov(&mut self, to: Id, col: usize) {
|
||||||
|
let Some(id) = self.is_dragged.take() else {return};
|
||||||
|
assert!(col <= COLS, "The col should be less then: {COLS}");
|
||||||
|
|
||||||
|
// Should be a better way to do this!
|
||||||
|
for container_data in self.containers_data.values_mut() {
|
||||||
|
for ids in container_data {
|
||||||
|
ids.retain(|i| *i != id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(container_data) = self.containers_data.get_mut(&to) {
|
||||||
|
container_data[col].push(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dragging(&mut self, id: Id) {
|
||||||
|
self.is_dragged = Some(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui.separator();
|
||||||
|
ui.label("Drag and drop:");
|
||||||
|
ui.columns(COLS, |ui| {
|
||||||
|
for col in 0..COLS {
|
||||||
|
let data = DATA.get().unwrap();
|
||||||
|
let ui = &mut ui[col];
|
||||||
|
let mut is_dragged = None;
|
||||||
|
let res = drop_target(ui, |ui| {
|
||||||
|
ui.set_min_height(60.0);
|
||||||
|
for (id, value) in data.read().cols(container_id, col) {
|
||||||
|
drag_source(ui, id, |ui| {
|
||||||
|
ui.add(egui::Label::new(value).sense(egui::Sense::click()));
|
||||||
|
if ui.memory(|mem| mem.is_being_dragged(id)) {
|
||||||
|
is_dragged = Some(id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if let Some(id) = is_dragged {
|
||||||
|
data.write().dragging(id);
|
||||||
|
}
|
||||||
|
if res.response.hovered() && ui.input(|i| i.pointer.any_released()) {
|
||||||
|
data.write().mov(container_id, col);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
ui.separator();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
@@ -286,7 +462,7 @@ fn main() {
|
|||||||
#[cfg(feature = "wgpu")]
|
#[cfg(feature = "wgpu")]
|
||||||
renderer: eframe::Renderer::Wgpu,
|
renderer: eframe::Renderer::Wgpu,
|
||||||
|
|
||||||
initial_window_size: Some(egui::Vec2::new(400.0, 220.0)),
|
initial_window_size: Some(egui::Vec2::new(450.0, 300.0)),
|
||||||
..NativeOptions::default()
|
..NativeOptions::default()
|
||||||
},
|
},
|
||||||
Box::new(|_| Box::<App>::default()),
|
Box::new(|_| Box::<App>::default()),
|
||||||
|
|||||||
Reference in New Issue
Block a user