From 254cf4efecd16e0b7bd0a459246c5f3c33147d95 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Thu, 5 Aug 2021 21:28:49 +0300 Subject: [PATCH] box selection for curve editor --- rg3d-ui/src/curve/mod.rs | 145 ++++++++++++++++++++++++++++----------- 1 file changed, 106 insertions(+), 39 deletions(-) diff --git a/rg3d-ui/src/curve/mod.rs b/rg3d-ui/src/curve/mod.rs index c4ab73465..70a94229c 100644 --- a/rg3d-ui/src/curve/mod.rs +++ b/rg3d-ui/src/curve/mod.rs @@ -95,6 +95,12 @@ enum OperationContext { key: usize, left: bool, }, + BoxSelection { + // In local coordinates. + initial_mouse_pos: Vector2, + min: Cell>, + max: Cell>, + }, } #[derive(Clone)] @@ -135,6 +141,7 @@ impl> Control for CurveEditor { self.draw_grid(ctx); self.draw_curve(ctx); self.draw_keys(ctx); + self.draw_operation(ctx); } fn handle_routed_message( @@ -202,56 +209,98 @@ impl> Control for CurveEditor { ) } } - } - } else if let Some(selection) = self.selection.as_ref() { - if state.left == ButtonState::Pressed { - match selection { - Selection::Keys { keys } => { - self.operation_context = Some(OperationContext::DragKeys { - entries: keys - .iter() - .map(|k| DragEntry { - key: *k, - initial_position: self.keys[*k].position, - }) - .collect::>(), - initial_mouse_pos: local_mouse_pos, - }); - } - Selection::LeftTangent { key } => { - self.operation_context = - Some(OperationContext::DragTangent { - key: *key, - left: true, - }) - } - Selection::RightTangent { key } => { - self.operation_context = - Some(OperationContext::DragTangent { - key: *key, - left: false, - }) - } + OperationContext::BoxSelection { + initial_mouse_pos, + min, + max, + .. + } => { + min.set(local_mouse_pos.inf(initial_mouse_pos)); + max.set(local_mouse_pos.sup(initial_mouse_pos)); } + } + } else { + if state.left == ButtonState::Pressed { + if let Some(selection) = self.selection.as_ref() { + match selection { + Selection::Keys { keys } => { + self.operation_context = + Some(OperationContext::DragKeys { + entries: keys + .iter() + .map(|k| DragEntry { + key: *k, + initial_position: self.keys[*k] + .position, + }) + .collect::>(), + initial_mouse_pos: local_mouse_pos, + }); + } + Selection::LeftTangent { key } => { + self.operation_context = + Some(OperationContext::DragTangent { + key: *key, + left: true, + }) + } + Selection::RightTangent { key } => { + self.operation_context = + Some(OperationContext::DragTangent { + key: *key, + left: false, + }) + } + } - if self.operation_context.is_some() { - ui.capture_mouse(self.handle); + if self.operation_context.is_some() { + ui.capture_mouse(self.handle); + } + } else { + self.operation_context = Some(OperationContext::BoxSelection { + initial_mouse_pos: local_mouse_pos, + min: Default::default(), + max: Default::default(), + }) } } } } - WidgetMessage::MouseUp { .. } => { + WidgetMessage::MouseUp { pos, .. } => { if let Some(context) = self.operation_context.take() { ui.release_mouse_capture(); // Send modified curve back to user. - if let OperationContext::DragKeys { .. } - | OperationContext::DragTangent { .. } = context - { - // Ensure that the order of keys is correct. - self.sort_keys(); + match context { + OperationContext::DragKeys { .. } + | OperationContext::DragTangent { .. } => { + // Ensure that the order of keys is correct. + self.sort_keys(); - self.send_curve(ui); + self.send_curve(ui); + } + OperationContext::BoxSelection { min, max, .. } => { + let min = min.get(); + let max = max.get(); + + let rect = + Rect::new(min.x, min.y, max.x - min.x, max.y - min.y); + + let mut selection = HashSet::default(); + for (i, key) in self.keys.iter().enumerate() { + if rect.contains(key.position) { + selection.insert(i); + } + } + + if !selection.is_empty() { + self.set_selection( + Some(Selection::Keys { keys: selection }), + ui, + ); + } + } + _ => {} } } } @@ -962,6 +1011,24 @@ impl> CurveEditor { ); } } + + fn draw_operation(&self, ctx: &mut DrawingContext) { + if let Some(op) = self.operation_context.as_ref() { + if let OperationContext::BoxSelection { min, max, .. } = op { + let min = self.point_to_screen_space(min.get()); + let max = self.point_to_screen_space(max.get()); + let rect = Rect::new(min.x, min.y, max.x - min.x, max.y - min.y); + + ctx.push_rect(&rect, 1.0); + ctx.commit( + self.screen_bounds(), + Brush::Solid(Color::WHITE), + CommandTexture::None, + None, + ); + } + } + } } pub struct CurveEditorBuilder> {