mirror of
https://github.com/a-b-street/abstreet.git
synced 2024-12-27 00:12:55 +03:00
Dragon drop poof of conscepter
This commit is contained in:
parent
b397f97a12
commit
0d028d1bb7
@ -8,6 +8,7 @@
|
||||
//! * [`Button`] - clickable buttons with keybindings and tooltips
|
||||
//! * [`Toggle`] - checkboxes, switches, and other toggles
|
||||
//! * [`CompareTimes`] - a scatter plot specialized for comparing times
|
||||
//! * [`DragDrop`] - a reorderable row of draggable cards
|
||||
//! * [`DrawWithTooltips`] - draw static geometry, with mouse tooltips in certain regions
|
||||
//! * [`Dropdown`] - a button that expands into a menu
|
||||
//! * [`FanChart`] - visualize a range of values over time
|
||||
@ -54,6 +55,7 @@ pub use crate::widgets::autocomplete::Autocomplete;
|
||||
pub(crate) use crate::widgets::button::Button;
|
||||
pub use crate::widgets::button::{ButtonBuilder, MultiButton};
|
||||
pub use crate::widgets::compare_times::CompareTimes;
|
||||
pub use crate::widgets::drag_drop::DragDrop;
|
||||
pub(crate) use crate::widgets::dropdown::Dropdown;
|
||||
pub use crate::widgets::fan_chart::FanChart;
|
||||
pub use crate::widgets::filler::Filler;
|
||||
|
119
widgetry/src/widgets/drag_drop.rs
Normal file
119
widgetry/src/widgets/drag_drop.rs
Normal file
@ -0,0 +1,119 @@
|
||||
use crate::{
|
||||
Drawable, EventCtx, GeomBatch, GeomBatchStack, GfxCtx, RewriteColor, ScreenDims, ScreenPt,
|
||||
ScreenRectangle, Widget, WidgetImpl, WidgetOutput,
|
||||
};
|
||||
|
||||
pub struct DragDrop<K: Clone> {
|
||||
members: Vec<(K, GeomBatch, ScreenDims)>,
|
||||
draw: Drawable,
|
||||
hovering: Option<usize>,
|
||||
dragging: Option<usize>,
|
||||
|
||||
dims: ScreenDims,
|
||||
top_left: ScreenPt,
|
||||
}
|
||||
|
||||
impl<K: 'static + Clone> DragDrop<K> {
|
||||
pub fn new_widget(ctx: &EventCtx, members: Vec<(K, GeomBatch)>) -> Widget {
|
||||
let mut dd = DragDrop {
|
||||
members: members
|
||||
.into_iter()
|
||||
.map(|(key, batch)| {
|
||||
let dims = batch.get_dims();
|
||||
(key, batch, dims)
|
||||
})
|
||||
.collect(),
|
||||
draw: Drawable::empty(ctx),
|
||||
hovering: None,
|
||||
dragging: None,
|
||||
|
||||
dims: ScreenDims::square(0.0),
|
||||
top_left: ScreenPt::new(0.0, 0.0),
|
||||
};
|
||||
dd.recalc_draw(ctx);
|
||||
Widget::new(Box::new(dd))
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: 'static + Clone> DragDrop<K> {
|
||||
fn recalc_draw(&mut self, ctx: &EventCtx) {
|
||||
let mut stack = GeomBatchStack::horizontal(Vec::new());
|
||||
for (idx, (_, batch, _)) in self.members.iter().enumerate() {
|
||||
let mut batch = batch.clone();
|
||||
if let Some(drag_idx) = self.dragging {
|
||||
// If we're dragging, fade everything out except what we're dragging and where
|
||||
// we're maybe going to drop
|
||||
if idx == drag_idx {
|
||||
// Leave it
|
||||
} else if self.hovering == Some(idx) {
|
||||
// Possible drop
|
||||
batch = batch.color(RewriteColor::ChangeAlpha(0.8));
|
||||
} else {
|
||||
// Fade it out
|
||||
batch = batch.color(RewriteColor::ChangeAlpha(0.5));
|
||||
}
|
||||
} else if self.hovering == Some(idx) {
|
||||
// If we're not dragging, show what we're hovering on
|
||||
batch = batch.color(RewriteColor::ChangeAlpha(0.5));
|
||||
}
|
||||
stack.push(batch);
|
||||
}
|
||||
let batch = stack.batch();
|
||||
self.dims = batch.get_dims();
|
||||
self.draw = batch.upload(ctx);
|
||||
}
|
||||
|
||||
fn mouseover_card(&self, ctx: &EventCtx) -> Option<usize> {
|
||||
let pt = ctx.canvas.get_cursor_in_screen_space()?;
|
||||
let mut top_left = self.top_left;
|
||||
for (idx, (_, _, dims)) in self.members.iter().enumerate() {
|
||||
if ScreenRectangle::top_left(top_left, *dims).contains(pt) {
|
||||
return Some(idx);
|
||||
}
|
||||
top_left.x += dims.width;
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<K: 'static + Clone> WidgetImpl for DragDrop<K> {
|
||||
fn get_dims(&self) -> ScreenDims {
|
||||
self.dims
|
||||
}
|
||||
|
||||
fn set_pos(&mut self, top_left: ScreenPt) {
|
||||
self.top_left = top_left;
|
||||
}
|
||||
|
||||
fn event(&mut self, ctx: &mut EventCtx, _: &mut WidgetOutput) {
|
||||
if let Some(old_idx) = self.dragging {
|
||||
if ctx.input.left_mouse_button_released() {
|
||||
self.dragging = None;
|
||||
if let Some(new_idx) = self.hovering {
|
||||
if old_idx != new_idx {
|
||||
// TODO Emit a Changed event, then the caller can go fetch the new ordering
|
||||
self.members.swap(old_idx, new_idx);
|
||||
self.recalc_draw(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if ctx.redo_mouseover() {
|
||||
let old = self.hovering.take();
|
||||
self.hovering = self.mouseover_card(ctx);
|
||||
if old != self.hovering {
|
||||
self.recalc_draw(ctx);
|
||||
}
|
||||
}
|
||||
if let Some(idx) = self.hovering {
|
||||
if ctx.input.left_mouse_button_pressed() {
|
||||
self.dragging = Some(idx);
|
||||
self.recalc_draw(ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn draw(&self, g: &mut GfxCtx) {
|
||||
g.redraw_at(self.top_left, &self.draw);
|
||||
}
|
||||
}
|
@ -21,6 +21,7 @@ pub mod autocomplete;
|
||||
pub mod button;
|
||||
pub mod compare_times;
|
||||
pub mod containers;
|
||||
pub mod drag_drop;
|
||||
pub mod dropdown;
|
||||
pub mod fan_chart;
|
||||
pub mod filler;
|
||||
|
@ -5,7 +5,7 @@ use rand_xorshift::XorShiftRng;
|
||||
|
||||
use geom::{Angle, Duration, Percent, Polygon, Pt2D, Time};
|
||||
use widgetry::{
|
||||
lctrl, Choice, Color, ContentMode, Drawable, EventCtx, Fill, GeomBatch, GfxCtx,
|
||||
lctrl, Choice, Color, ContentMode, DragDrop, Drawable, EventCtx, Fill, GeomBatch, GfxCtx,
|
||||
HorizontalAlignment, Image, Key, Line, LinePlot, Outcome, Panel, PersistentSplit, PlotOptions,
|
||||
ScreenDims, Series, Settings, SharedAppState, State, TabController, Text, TextExt, Texture,
|
||||
Toggle, Transition, UpdateType, VerticalAlignment, Widget,
|
||||
@ -315,12 +315,17 @@ fn setup_scrollable_canvas(ctx: &mut EventCtx) -> Drawable {
|
||||
}
|
||||
|
||||
fn make_tabs(ctx: &mut EventCtx) -> TabController {
|
||||
let draggable_cards = (0..5)
|
||||
.map(|i| (i, make_draggable_card(ctx, i)))
|
||||
.collect::<Vec<_>>();
|
||||
let style = ctx.style();
|
||||
|
||||
let mut tabs = TabController::new("demo_tabs");
|
||||
|
||||
let gallery_bar_item = style.btn_tab.text("Component Gallery");
|
||||
let gallery_content = Widget::col(vec![
|
||||
"Reorder the cards below".text_widget(ctx),
|
||||
DragDrop::new_widget(ctx, draggable_cards),
|
||||
Text::from(Line("Text").big_heading_styled().size(18)).into_widget(ctx),
|
||||
Text::from_all(vec![
|
||||
Line("You can "),
|
||||
@ -604,6 +609,14 @@ fn make_controls(ctx: &mut EventCtx, tabs: &mut TabController) -> Panel {
|
||||
.build(ctx)
|
||||
}
|
||||
|
||||
fn make_draggable_card(ctx: &mut EventCtx, num: usize) -> GeomBatch {
|
||||
// TODO Kind of hardcoded. At least center the text or draw nice outlines?
|
||||
let mut batch = GeomBatch::new();
|
||||
batch.push(Color::RED, Polygon::rectangle(100.0, 150.0));
|
||||
batch.append(Text::from(format!("Card {}", num)).render(ctx));
|
||||
batch
|
||||
}
|
||||
|
||||
// Boilerplate for web support
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
|
Loading…
Reference in New Issue
Block a user